diff --git a/lamagraph-compiler/src/Lamagraph/Compiler/Core/LmlToCore.hs b/lamagraph-compiler/src/Lamagraph/Compiler/Core/LmlToCore.hs index 35b4f157..a332f607 100644 --- a/lamagraph-compiler/src/Lamagraph/Compiler/Core/LmlToCore.hs +++ b/lamagraph-compiler/src/Lamagraph/Compiler/Core/LmlToCore.hs @@ -4,10 +4,13 @@ import Relude import Control.Monad.Extra import Data.Foldable.Extra hiding (elem) +import Data.List (partition, (!!)) +import Data.List.NonEmpty qualified as NE import Lamagraph.Compiler.Core import Lamagraph.Compiler.Core.MonadDesugar import Lamagraph.Compiler.Extension +import Lamagraph.Compiler.ModuleResolver.DefaultEnv (stdPrefix) import Lamagraph.Compiler.ModuleResolver.Types import Lamagraph.Compiler.Parser.SrcLoc import Lamagraph.Compiler.Syntax @@ -33,7 +36,7 @@ desugarLmlExpr = \case LmlExprMatch _ lExpr lCases -> do scrutineeVar <- freshVar expr <- desugarLLmlExpr lExpr - cases <- mapM (desugarLLmlCase scrutineeVar) lCases + cases <- compilePatterns scrutineeVar lCases pure $ Match expr scrutineeVar cases LmlExprTuple _ lExpr lExprs -> Tuple <$> desugarLLmlExpr lExpr <*> mapM desugarLLmlExpr lExprs LmlExprConstruct _ (L _ longident) maybeArgs -> @@ -51,11 +54,603 @@ desugarLmlExpr = \case pure $ Match condExpr var (trueAlt :| [falseAlt]) LmlExprConstraint _ lExpr _ -> desugarLLmlExpr lExpr +expandOrPatterns :: NonEmpty (LLmlCase LmlcTc) -> NonEmpty (LLmlCase LmlcTc) +expandOrPatterns cases = + let expanded = concatMap expandCase (toList cases) + in fromMaybe cases (nonEmpty expanded) + where + expandCase :: LLmlCase LmlcTc -> [LLmlCase LmlcTc] + expandCase (L loc (LmlCase ty pat guardExpr rhs)) = + let expandedPats = expandPat pat + in [L loc (LmlCase ty p guardExpr rhs) | p <- expandedPats] + + expandPat :: LLmlPat LmlcTc -> [LLmlPat LmlcTc] + expandPat lPat@(L loc pat) = case pat of + LmlPatOr _ p1 p2 -> + expandPat p1 ++ expandPat p2 + LmlPatConstruct x name maybeSub -> + case maybeSub of + Nothing -> [lPat] + Just sub -> + let expandedSubs = expandPat sub + in [L loc (LmlPatConstruct x name (Just s)) | s <- expandedSubs] + LmlPatTuple x p1 ps -> + let allPats = p1 : toList ps + expandedPats = map expandPat allPats + combinations = sequence expandedPats + buildTuple (firstPat : rest) = case nonEmpty rest of + Just restNE -> Just (L loc (LmlPatTuple x firstPat restNE)) + Nothing -> Nothing + buildTuple [] = Nothing + in mapMaybe buildTuple combinations + LmlPatConstraint x p ty -> + [L loc (LmlPatConstraint x expanded ty) | expanded <- expandPat p] + _ -> [lPat] + +compilePatterns :: Var -> NonEmpty (LLmlCase LmlcTc) -> MonadDesugar (NonEmpty CoreMatchAlt) +compilePatterns scrutineeVar lCases = do + let expandedCases = expandOrPatterns lCases + + let hasGuards = any caseHasGuard expandedCases + + if hasGuards + then compilePatternsWithBacktracking scrutineeVar expandedCases + else compilePatternsOriginal scrutineeVar expandedCases + +caseHasGuard :: LLmlCase LmlcTc -> Bool +caseHasGuard (L _ (LmlCase _ _ maybeGuard _)) = isJust maybeGuard + +compilePatternsOriginal :: Var -> NonEmpty (LLmlCase LmlcTc) -> MonadDesugar (NonEmpty CoreMatchAlt) +compilePatternsOriginal scrut cases = do + alts <- groupAndCompileCases scrut (toList cases) + case nonEmpty alts of + Just altsNE -> pure altsNE + Nothing -> pure $ pure (DEFAULT, [], Var scrut) + +groupAndCompileCases :: Var -> [LLmlCase LmlcTc] -> MonadDesugar [CoreMatchAlt] +groupAndCompileCases _ [] = pure [] +groupAndCompileCases scrut (firstCase : restCases) = do + let (sameGroup, different) = partition (sameOuterPatternNoGuard firstCase) restCases + currentGroup = firstCase :| sameGroup + + compiledGroup <- compilePatternGroupOriginal scrut currentGroup + compiledRest <- groupAndCompileCases scrut different + + pure (compiledGroup : compiledRest) + +sameOuterPatternNoGuard :: LLmlCase LmlcTc -> LLmlCase LmlcTc -> Bool +sameOuterPatternNoGuard (L _ (LmlCase _ (L _ pat1) _ _)) (L _ (LmlCase _ (L _ pat2) _ _)) = + samePat pat1 pat2 + where + samePat :: LmlPat LmlcTc -> LmlPat LmlcTc -> Bool + samePat (LmlPatConstruct _ (L _ name1) _) (LmlPatConstruct _ (L _ name2) _) = name1 == name2 + samePat (LmlPatAny _) (LmlPatAny _) = True + samePat (LmlPatVar{}) (LmlPatVar{}) = True + samePat (LmlPatVar{}) (LmlPatAny _) = True + samePat (LmlPatAny _) (LmlPatVar{}) = True + samePat (LmlPatTuple{}) (LmlPatTuple{}) = True + samePat (LmlPatConstant _ lit1) (LmlPatConstant _ lit2) = sameLiteral lit1 lit2 + samePat _ _ = False + + sameLiteral :: LmlLit LmlcTc -> LmlLit LmlcTc -> Bool + sameLiteral (LmlInt _ n1) (LmlInt _ n2) = n1 == n2 + sameLiteral (LmlChar _ c1) (LmlChar _ c2) = c1 == c2 + sameLiteral (LmlString _ s1) (LmlString _ s2) = s1 == s2 + sameLiteral _ _ = False + +compilePatternGroupOriginal :: Var -> NonEmpty (LLmlCase LmlcTc) -> MonadDesugar CoreMatchAlt +compilePatternGroupOriginal scrut (singleCase@(L _ (LmlCase ty (L _ pat) _ _)) :| []) = + case pat of + LmlPatConstruct _ (L _ constrName) maybeSub -> + case maybeSub of + Nothing -> desugarLLmlCase scrut singleCase + Just _ -> compileConstructorGroup scrut ty (Name constrName) (singleCase :| []) + LmlPatTuple{} -> + compileTupleGroup scrut ty (singleCase :| []) + _ -> + desugarLLmlCase scrut singleCase +compilePatternGroupOriginal scrut cases@(firstCase :| _) = + case firstCase of + L _ (LmlCase ty (L _ firstPat) _ _) -> case firstPat of + LmlPatConstruct _ (L _ constrName) _ -> + compileConstructorGroup scrut ty (Name constrName) cases + LmlPatTuple{} -> + compileTupleGroup scrut ty cases + LmlPatVar{} -> + desugarLLmlCase scrut firstCase + LmlPatAny _ -> + desugarLLmlCase scrut firstCase + _ -> + desugarLLmlCase scrut firstCase + +compilePatternsWithBacktracking :: Var -> NonEmpty (LLmlCase LmlcTc) -> MonadDesugar (NonEmpty CoreMatchAlt) +compilePatternsWithBacktracking scrutineeVar cases = do + compiled <- compileCasesWithFallback scrutineeVar (toList cases) (Var scrutineeVar) + + case nonEmpty compiled of + Just alts -> pure alts + Nothing -> pure $ pure (DEFAULT, [], Var scrutineeVar) + +compileCasesWithFallback :: Var -> [LLmlCase LmlcTc] -> CoreExpr -> MonadDesugar [CoreMatchAlt] +compileCasesWithFallback _ [] _fallback = pure [] +compileCasesWithFallback scrut (firstCase : restCases) fallback = do + let isDefaultCase (L _ (LmlCase _ (L _ pat) _ _)) = case pat of + LmlPatVar{} -> True + LmlPatAny _ -> True + _ -> False + isDefaultCase (L _ (XLmlCase _)) = False + + if isDefaultCase firstCase + then do + let allDefaultCases = firstCase : filter isDefaultCase restCases + nonDefaultCases = filter (not . isDefaultCase) restCases + + nonDefaultAlts <- + if null nonDefaultCases + then pure [] + else compileCasesWithFallback scrut nonDefaultCases fallback + + defaultFallback <- + if null nonDefaultCases + then pure fallback + else case nonEmpty nonDefaultAlts of + Just alts -> pure $ Match (Var scrut) scrut alts + Nothing -> pure fallback + + singleDefaultAlt <- compileDefaultCasesChain scrut allDefaultCases defaultFallback + + pure (singleDefaultAlt : nonDefaultAlts) + else do + let (sameGroup, different) = partition (sameOuterPattern firstCase) restCases + currentGroup = firstCase :| sameGroup + + remainingAlts <- + if null different + then pure [] + else compileCasesWithFallback scrut different fallback + + let remainingFallback = case nonEmpty remainingAlts of + Just alts -> Match (Var scrut) scrut alts + Nothing -> fallback + + compiledGroup <- compilePatternGroupWithFallback scrut currentGroup remainingFallback + + pure (compiledGroup : remainingAlts) + +compileDefaultCasesChain :: Var -> [LLmlCase LmlcTc] -> CoreExpr -> MonadDesugar CoreMatchAlt +compileDefaultCasesChain _scrut [] fallback = + pure (DEFAULT, [], fallback) +compileDefaultCasesChain scrut (firstCase : restCases) fallback = do + remainingFallback <- + if null restCases + then pure fallback + else do + (_, _, rhs) <- compileDefaultCasesChain scrut restCases fallback + pure rhs + + (_, _, rhs) <- desugarLmlCaseWithFallback scrut firstCase remainingFallback + + pure (DEFAULT, [], rhs) + +sameOuterPattern :: LLmlCase LmlcTc -> LLmlCase LmlcTc -> Bool +sameOuterPattern (L _ (LmlCase _ (L _ pat1) guard1 _)) (L _ (LmlCase _ (L _ pat2) guard2 _)) = + isNothing guard1 && isNothing guard2 && samePat pat1 pat2 + where + samePat :: LmlPat LmlcTc -> LmlPat LmlcTc -> Bool + samePat (LmlPatConstruct _ (L _ name1) _) (LmlPatConstruct _ (L _ name2) _) = name1 == name2 + samePat (LmlPatTuple{}) (LmlPatTuple{}) = True + samePat (LmlPatConstant _ lit1) (LmlPatConstant _ lit2) = sameLiteral lit1 lit2 + samePat _ _ = False + + sameLiteral :: LmlLit LmlcTc -> LmlLit LmlcTc -> Bool + sameLiteral (LmlInt _ n1) (LmlInt _ n2) = n1 == n2 + sameLiteral (LmlChar _ c1) (LmlChar _ c2) = c1 == c2 + sameLiteral (LmlString _ s1) (LmlString _ s2) = s1 == s2 + sameLiteral _ _ = False + +compilePatternGroupWithFallback :: Var -> NonEmpty (LLmlCase LmlcTc) -> CoreExpr -> MonadDesugar CoreMatchAlt +compilePatternGroupWithFallback scrut (singleCase@(L _ (LmlCase ty (L _ pat) _maybeGuard _)) :| []) fallback = + case pat of + LmlPatConstruct _ (L _ constrName) maybeSub -> + case maybeSub of + Nothing -> desugarLmlCaseWithFallback scrut singleCase fallback + Just _ -> compileConstructorGroupWithFallback scrut ty (Name constrName) (singleCase :| []) fallback + LmlPatTuple{} -> + compileTupleGroupWithFallback scrut ty (singleCase :| []) fallback + _ -> + desugarLmlCaseWithFallback scrut singleCase fallback +compilePatternGroupWithFallback scrut cases@(firstCase :| _) fallback = + case firstCase of + L _ (LmlCase ty (L _ firstPat) _ _) -> case firstPat of + LmlPatConstruct _ (L _ constrName) _ -> + compileConstructorGroupWithFallback scrut ty (Name constrName) cases fallback + LmlPatTuple{} -> + compileTupleGroupWithFallback scrut ty cases fallback + LmlPatVar{} -> + desugarLmlCaseWithFallback scrut firstCase fallback + LmlPatAny _ -> + desugarLmlCaseWithFallback scrut firstCase fallback + _ -> + desugarLmlCaseWithFallback scrut firstCase fallback + +compileConstructorGroup :: Var -> Ty -> Name -> NonEmpty (LLmlCase LmlcTc) -> MonadDesugar CoreMatchAlt +compileConstructorGroup scrut ty constrName cases@(firstCase :| _) = do + let subPatternSets = NE.map extractConstructorSubPatterns cases + + if all isSimpleVarPattern (toList subPatternSets) + then do + desugarLLmlCase scrut firstCase + else do + compileNestedConstructorMatch scrut ty constrName cases subPatternSets + +compileConstructorGroupWithFallback :: + Var -> Ty -> Name -> NonEmpty (LLmlCase LmlcTc) -> CoreExpr -> MonadDesugar CoreMatchAlt +compileConstructorGroupWithFallback scrut ty constrName cases fallback = do + let subPatternSets = NE.map extractConstructorSubPatterns cases + firstCase = NE.head cases + + if all isSimpleVarPattern (toList subPatternSets) + then desugarLmlCaseWithFallback scrut firstCase fallback + else compileNestedConstructorMatchWithFallback scrut ty constrName (toList cases) (toList subPatternSets) fallback + +extractConstructorSubPatterns :: LLmlCase LmlcTc -> Maybe (NonEmpty (LLmlPat LmlcTc)) +extractConstructorSubPatterns (L _ (LmlCase _ (L _ (LmlPatConstruct _ _ maybeLPat)) _ _)) = + case maybeLPat of + Nothing -> Nothing + Just (L _ (LmlPatTuple _ p1 ps)) -> Just (p1 :| toList ps) + Just (L loc singlePat) -> Just (L loc singlePat :| []) +extractConstructorSubPatterns _ = Nothing + +isSimpleVarPattern :: Maybe (NonEmpty (LLmlPat LmlcTc)) -> Bool +isSimpleVarPattern Nothing = True +isSimpleVarPattern (Just pats) = all isSimpleVar (toList pats) + where + isSimpleVar :: LLmlPat LmlcTc -> Bool + isSimpleVar (L _ (LmlPatVar{})) = True + isSimpleVar (L _ (LmlPatAny _)) = True + isSimpleVar _ = False + +compileNestedConstructorMatch :: + Var -> + Ty -> + Name -> + NonEmpty (LLmlCase LmlcTc) -> + NonEmpty (Maybe (NonEmpty (LLmlPat LmlcTc))) -> + MonadDesugar CoreMatchAlt +compileNestedConstructorMatch _scrut ty constrName cases (firstSet :| restSets) = do + let arity = maybe 0 length firstSet + + argVars <- replicateM arity freshVar + + let rhsExprs = map extractRHS (toList cases) + subPatternSets = firstSet : restSets + + nestedExpr <- buildNestedMatchForPosition argVars 0 ty (zip subPatternSets rhsExprs) + + pure (DataAlt constrName, argVars, nestedExpr) + +compileNestedConstructorMatchWithFallback :: + Var -> Ty -> Name -> [LLmlCase LmlcTc] -> [Maybe (NonEmpty (LLmlPat LmlcTc))] -> CoreExpr -> MonadDesugar CoreMatchAlt +compileNestedConstructorMatchWithFallback _scrut ty constrName cases subPatternSets fallback = do + let arity = case listToMaybe subPatternSets of + Nothing -> 0 + Just Nothing -> 0 + Just (Just pats) -> length pats + + argVars <- replicateM arity freshVar + + nestedExpr <- buildNestedMatchWithFallback argVars 0 ty cases subPatternSets fallback + + pure (DataAlt constrName, argVars, nestedExpr) + +buildNestedMatchWithFallback :: + [Var] -> Int -> Ty -> [LLmlCase LmlcTc] -> [Maybe (NonEmpty (LLmlPat LmlcTc))] -> CoreExpr -> MonadDesugar CoreExpr +buildNestedMatchWithFallback argVars pos ty cases subPatternSets fallback = do + let casesWithPats = zip cases subPatternSets + groupedByPattern = groupCasesBySubPatternAt pos casesWithPats + + alts <- mapM (compileSubPatternGroupWithFallback argVars pos ty fallback) groupedByPattern + + case nonEmpty alts of + Nothing -> pure fallback + Just altsNE -> do + let scrutVar = argVars !! pos + pure $ Match (Var scrutVar) scrutVar altsNE + +groupCasesBySubPatternAt :: + Int -> [(LLmlCase LmlcTc, Maybe (NonEmpty (LLmlPat LmlcTc)))] -> [[(LLmlCase LmlcTc, Maybe (LLmlPat LmlcTc))]] +groupCasesBySubPatternAt pos casePairs = + let extracted = map (second (getPatternAt pos)) casePairs + grouped = groupByPatternType extracted + in grouped + where + getPatternAt :: Int -> Maybe (NonEmpty (LLmlPat LmlcTc)) -> Maybe (LLmlPat LmlcTc) + getPatternAt _ Nothing = Nothing + getPatternAt idx (Just pats) = listToMaybe (drop idx (toList pats)) + + groupByPatternType :: [(LLmlCase LmlcTc, Maybe (LLmlPat LmlcTc))] -> [[(LLmlCase LmlcTc, Maybe (LLmlPat LmlcTc))]] + groupByPatternType [] = [] + groupByPatternType (p : ps) = + let (same, diff) = partition (samePatType p) ps + in (p : same) : groupByPatternType diff + + samePatType (_, Nothing) (_, Nothing) = True + samePatType (_, Just (L _ p1)) (_, Just (L _ p2)) = + case (p1, p2) of + (LmlPatConstruct _ (L _ n1) _, LmlPatConstruct _ (L _ n2) _) -> n1 == n2 + (LmlPatVar{}, LmlPatVar{}) -> True + (LmlPatAny _, LmlPatAny _) -> True + (LmlPatVar{}, LmlPatAny _) -> True + (LmlPatAny _, LmlPatVar{}) -> True + _ -> False + samePatType _ _ = False + + samePatType :: (LLmlCase LmlcTc, Maybe (LLmlPat LmlcTc)) -> (LLmlCase LmlcTc, Maybe (LLmlPat LmlcTc)) -> Bool + +compileSubPatternGroupWithFallback :: + [Var] -> Int -> Ty -> CoreExpr -> [(LLmlCase LmlcTc, Maybe (LLmlPat LmlcTc))] -> MonadDesugar CoreMatchAlt +compileSubPatternGroupWithFallback _argVars _pos _ty fallback [] = + pure (DEFAULT, [], fallback) +compileSubPatternGroupWithFallback argVars pos _ty fallback ((firstCase, firstPat) : _rest) = case firstPat of + Nothing -> do + let scrutVar = argVars !! pos + desugarLmlCaseWithFallback scrutVar firstCase fallback + Just (L _ (LmlPatVar (FullName n, _) _)) -> do + let (L _ (LmlCase _ _ maybeGuard rhs)) = firstCase + rhsCore <- desugarLLmlExpr rhs + + finalRhs <- case maybeGuard of + Nothing -> pure rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + + let boundVar = Id $ Name n + let scrutVar = argVars !! pos + pure (DEFAULT, [], replaceVar boundVar scrutVar finalRhs) + Just (L _ (LmlPatAny _)) -> do + let (L _ (LmlCase _ _ maybeGuard rhs)) = firstCase + rhsCore <- desugarLLmlExpr rhs + + finalRhs <- case maybeGuard of + Nothing -> pure rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + + pure (DEFAULT, [], finalRhs) + Just (L _ (LmlPatConstruct _ (L _ constrName) maybeSub)) -> do + case maybeSub of + Nothing -> do + let (L _ (LmlCase _ _ maybeGuard rhs)) = firstCase + rhsCore <- desugarLLmlExpr rhs + + finalRhs <- case maybeGuard of + Nothing -> pure rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + + pure (DataAlt (Name constrName), [], finalRhs) + Just subPat -> do + let patternGroup = (firstCase, firstPat) : _rest + allCasesInGroup = map fst patternGroup + hasGuards = any (\(L _ (LmlCase _ _ g _)) -> isJust g) allCasesInGroup + isComplexNesting = case subPat of + L _ (LmlPatTuple _ p ps) -> not $ all isSimpleVarOrWildcard (p : toList ps) + _ -> False + + let scrutVar = argVars !! pos + if isComplexNesting && hasGuards + then do + let buildNestedCase (L caseLoc (LmlCase caseTy _ maybeGuard rhs), _) = + L caseLoc (LmlCase caseTy subPat maybeGuard rhs) + nestedCases = map buildNestedCase patternGroup + + case nonEmpty nestedCases of + Nothing -> do + pure (DEFAULT, [], fallback) + Just nestedCasesNE -> do + nestedAlts <- compilePatternsWithBacktracking scrutVar nestedCasesNE + pure (NE.head nestedAlts) + else do + let (L caseLoc (LmlCase caseTy _ maybeGuard rhs)) = firstCase + newCase = L caseLoc (LmlCase caseTy subPat maybeGuard rhs) + desugarLmlCaseWithFallback scrutVar newCase fallback + Just subPat -> do + let (L caseLoc (LmlCase caseTy _ maybeGuard rhs)) = firstCase + newCase = L caseLoc (LmlCase caseTy subPat maybeGuard rhs) + let scrutVar = argVars !! pos + desugarLmlCaseWithFallback scrutVar newCase fallback + +extractRHS :: LLmlCase LmlcTc -> LLmlExpr LmlcTc +extractRHS (L _ (LmlCase _ _ _ rhs)) = rhs + +buildNestedMatchForPosition :: + [Var] -> Int -> Ty -> [(Maybe (NonEmpty (LLmlPat LmlcTc)), LLmlExpr LmlcTc)] -> MonadDesugar CoreExpr +buildNestedMatchForPosition argVars pos ty casePairs = do + let groupedByPattern = groupCasesBySubPattern pos casePairs + + alts <- + Relude.mapMaybeM + ( \grp -> case nonEmpty grp of + Nothing -> pure Nothing + Just groupNE -> Just <$> compileSubPatternGroup argVars pos ty groupNE + ) + groupedByPattern + + case nonEmpty alts of + Nothing -> do + let scrutVar = argVars !! pos + pure $ Var scrutVar + Just altsNE -> do + let scrutVar = argVars !! pos + pure $ Match (Var scrutVar) scrutVar altsNE + +groupCasesBySubPattern :: + Int -> [(Maybe (NonEmpty (LLmlPat LmlcTc)), LLmlExpr LmlcTc)] -> [[(Maybe (LLmlPat LmlcTc), LLmlExpr LmlcTc)]] +groupCasesBySubPattern pos cases = + let extracted = map (first (getPatternAt pos)) cases + grouped = groupByPattern extracted + in grouped + where + getPatternAt :: Int -> Maybe (NonEmpty (LLmlPat LmlcTc)) -> Maybe (LLmlPat LmlcTc) + getPatternAt _ Nothing = Nothing + getPatternAt idx (Just pats) = listToMaybe (drop idx (toList pats)) + + groupByPattern :: [(Maybe (LLmlPat LmlcTc), LLmlExpr LmlcTc)] -> [[(Maybe (LLmlPat LmlcTc), LLmlExpr LmlcTc)]] + groupByPattern [] = [] + groupByPattern (p : ps) = + let (same, diff) = partition (samePatternType p) ps + in (p : same) : groupByPattern diff + + samePatternType (Nothing, _) (Nothing, _) = True + samePatternType (Just (L _ p1), _) (Just (L _ p2), _) = + case (p1, p2) of + (LmlPatConstruct _ (L _ n1) _, LmlPatConstruct _ (L _ n2) _) -> n1 == n2 + (LmlPatVar{}, LmlPatVar{}) -> True + (LmlPatAny _, LmlPatAny _) -> True + (LmlPatVar{}, LmlPatAny _) -> True + (LmlPatAny _, LmlPatVar{}) -> True + _ -> False + samePatternType _ _ = False + + samePatternType :: (Maybe (LLmlPat LmlcTc), LLmlExpr LmlcTc) -> (Maybe (LLmlPat LmlcTc), LLmlExpr LmlcTc) -> Bool + +compileSubPatternGroup :: + [Var] -> Int -> Ty -> NonEmpty (Maybe (LLmlPat LmlcTc), LLmlExpr LmlcTc) -> MonadDesugar CoreMatchAlt +compileSubPatternGroup argVars pos ty patternGroup@((firstPat, firstRHS) :| _) = case firstPat of + Nothing -> do + rhs <- desugarLLmlExpr firstRHS + pure (DEFAULT, [], rhs) + Just (L _ (LmlPatVar (FullName n, _) _)) -> do + rhs <- desugarLLmlExpr firstRHS + let boundVar = Id $ Name n + let scrutVar = argVars !! pos + pure (DEFAULT, [], replaceVar boundVar scrutVar rhs) + Just (L _ (LmlPatAny _)) -> do + rhs <- desugarLLmlExpr firstRHS + pure (DEFAULT, [], rhs) + Just (L _ (LmlPatConstruct _ (L _ constrName) maybeSub)) -> do + case maybeSub of + Nothing -> do + rhs <- desugarLLmlExpr firstRHS + pure (DataAlt (Name constrName), [], rhs) + Just (L _ subPat) -> do + let subPatterns = case subPat of + LmlPatTuple _ p ps -> p : toList ps + otherPat -> [L generatedSrcSpan otherPat] + arity = length subPatterns + + subVars <- replicateM arity freshVar + + let extractNestedPat (Just (L _ (LmlPatConstruct _ _ (Just (L _ constructorArg)))), rhs) = + let subs = case constructorArg of + LmlPatTuple _ p ps -> Just $ p :| toList ps + otherPat -> Just $ L generatedSrcSpan otherPat :| [] + in (subs, rhs) + extractNestedPat (Just (L _ (LmlPatConstruct _ _ Nothing)), rhs) = + (Nothing, rhs) + extractNestedPat (_, rhs) = (Nothing, rhs) + let nestedPatterns = NE.map extractNestedPat patternGroup + + case subVars of + [] -> do + rhs <- desugarLLmlExpr firstRHS + pure (DataAlt (Name constrName), [], rhs) + _ : _ -> do + nestedExpr <- buildNestedMatchForPosition subVars 0 ty (toList nestedPatterns) + pure (DataAlt (Name constrName), subVars, nestedExpr) + Just (L _ (LmlPatConstant _ lit)) -> do + rhs <- desugarLLmlExpr firstRHS + pure (LitAlt (desugarLmlLit lit), [], rhs) + _ -> do + rhs <- desugarLLmlExpr firstRHS + pure (DEFAULT, [], rhs) + +compileTupleGroup :: Var -> Ty -> NonEmpty (LLmlCase LmlcTc) -> MonadDesugar CoreMatchAlt +compileTupleGroup scrut _ty (firstCase :| _) = + desugarLLmlCase scrut firstCase + +compileTupleGroupWithFallback :: Var -> Ty -> NonEmpty (LLmlCase LmlcTc) -> CoreExpr -> MonadDesugar CoreMatchAlt +compileTupleGroupWithFallback scrut _ty cases = desugarLmlCaseWithFallback scrut (NE.head cases) + +desugarNestedPatHelper :: LLmlPat LmlcTc -> MonadDesugar (Var, Var -> CoreExpr -> CoreExpr) +desugarNestedPatHelper (L _ innerPat) = case innerPat of + LmlPatVar (FullName n, _) _ -> + pure (Id $ Name n, \_ rhs -> rhs) + LmlPatAny _ -> do + freshV <- freshVar + pure (freshV, \_ rhs -> rhs) + LmlPatConstraint _ lPat _ -> + desugarNestedPatHelper lPat + LmlPatOr{} -> error "FIXME: Or patterns in tuples aren't supported." + LmlPatConstruct _ (L _ constructorName) maybeLPat -> do + case maybeLPat of + Nothing -> do + freshV <- freshVar + pure (freshV, \_ rhs -> rhs) + Just (L _ subPat) -> case subPat of + LmlPatVar (FullName n, _) _ -> do + freshV <- freshVar + let fieldVar = Id $ Name n + matchVar <- freshVar + let wrapWithMatch _ rhs = + let alt = (DataAlt (Name constructorName), [fieldVar], rhs) + in Match (Var freshV) matchVar (alt :| []) + pure (freshV, wrapWithMatch) + LmlPatAny _ -> do + freshV <- freshVar + wildcardVar <- freshVar + matchVar <- freshVar + let wrapWithMatch _ rhs = + let alt = (DataAlt (Name constructorName), [wildcardVar], rhs) + in Match (Var freshV) matchVar (alt :| []) + pure (freshV, wrapWithMatch) + LmlPatTuple _ lPat lPats -> do + freshV <- freshVar + tupleVar <- freshVar + matchVar1 <- freshVar + + let tuplePatterns = lPat : toList lPats + tupleResults <- mapM desugarNestedPatHelper tuplePatterns + let (tupleVars, tupleWrappers) = unzip tupleResults + + matchVar2 <- freshVar + let wrapWithMatch _ rhs = + let wrappedRhs = foldr (\(var, wrapper) acc -> wrapper var acc) rhs (zip tupleVars tupleWrappers) + tupleAlt = (TupleAlt, tupleVars, wrappedRhs) + tupleMatch = Match (Var tupleVar) matchVar2 (tupleAlt :| []) + constructorAlt = (DataAlt (Name constructorName), [tupleVar], tupleMatch) + in Match (Var freshV) matchVar1 (constructorAlt :| []) + pure (freshV, wrapWithMatch) + _ -> do + freshV <- freshVar + pure (freshV, \_ rhs -> rhs) + _ -> do + freshV <- freshVar + pure (freshV, \_ rhs -> rhs) + desugarLLmlCase :: Var -> LLmlCase LmlcTc -> MonadDesugar CoreMatchAlt desugarLLmlCase scrutineeVar (L _ case') = desugarLmlCase scrutineeVar case' +isSimpleVarOrWildcard :: LLmlPat LmlcTc -> Bool +isSimpleVarOrWildcard (L _ (LmlPatVar{})) = True +isSimpleVarOrWildcard (L _ (LmlPatAny _)) = True +isSimpleVarOrWildcard (L _ (LmlPatConstraint _ lPat _)) = isSimpleVarOrWildcard lPat +isSimpleVarOrWildcard _ = False + desugarLmlCase :: Var -> LmlCase LmlcTc -> MonadDesugar CoreMatchAlt -desugarLmlCase scrutineeVar (LmlCase _ (L _ pat) Nothing lExpr) = do +desugarLmlCase scrutineeVar (LmlCase ty (L _ pat) Nothing lExpr) = do expr <- desugarLLmlExpr lExpr case pat of LmlPatAny _ -> pure (DEFAULT, [], expr) @@ -66,27 +661,191 @@ desugarLmlCase scrutineeVar (LmlCase _ (L _ pat) Nothing lExpr) = do , replaceVar (Id $ Name n) scrutineeVar expr ) LmlPatConstant _ lit -> pure (LitAlt $ desugarLmlLit lit, [], expr) - LmlPatTuple _ lPat lPats -> - let vars = map helper (lPat : toList lPats) - in pure (TupleAlt, vars, expr) + LmlPatTuple _ lPat lPats -> do + (vars, wrappers) <- mapAndUnzipM desugarNestedPatHelper (lPat : toList lPats) + let exprWithMatches = foldr (\(var, wrapper) acc -> wrapper var acc) expr (zip vars wrappers) + pure (TupleAlt, vars, exprWithMatches) LmlPatConstruct _ (L _ longident) maybeLPat -> let constuctorName = Name longident in case maybeLPat of Nothing -> pure (DataAlt constuctorName, [], expr) - Just (L _ args) -> + Just (L _ args) -> do case args of - LmlPatVar (FullName n, _) _ -> pure (DataAlt constuctorName, [Id $ Name n], expr) - LmlPatTuple _ lPat lPats -> - let vars = map helper (lPat : toList lPats) - in pure (DataAlt constuctorName, vars, expr) - _ -> error "Internal error: Constructors can only be applied to Var or Tuple." - LmlPatOr{} -> error "FIXME: Or patterns in match expressions aren't supported." - LmlPatConstraint{} -> error "FIXME: Constraints in pattern-matching are currently unsupported." - where - helper lPat = case unLoc lPat of - LmlPatVar (FullName n, _) _ -> Id $ Name n - _ -> error "FIXME: Nested patterns are currently unsupported." -desugarLmlCase _ (LmlCase _ _ (Just _) _) = error "FIXME: Guards in pattern-matching are currently unsupported." + LmlPatVar (FullName n, _) _ -> do + pure (DataAlt constuctorName, [Id $ Name n], expr) + LmlPatAny _ -> do + freshV <- freshVar + pure (DataAlt constuctorName, [freshV], expr) + LmlPatTuple _ lPat lPats -> do + let pats = lPat : toList lPats + allSimple = all isSimpleVarOrWildcard pats + if allSimple + then do + (vars, wrappers) <- mapAndUnzipM desugarNestedPatHelper pats + let exprWithMatches = foldr (\(var, wrapper) acc -> wrapper var acc) expr (zip vars wrappers) + pure (DataAlt constuctorName, vars, exprWithMatches) + else do + vars <- replicateM (length pats) freshVar + pure (DataAlt constuctorName, vars, expr) + LmlPatConstruct{} -> do + freshV <- freshVar + pure (DataAlt constuctorName, [freshV], expr) + _ -> do + freshV <- freshVar + pure (DataAlt constuctorName, [freshV], expr) + LmlPatOr{} -> error "FIXME: Or patterns in constructors aren't supported." + LmlPatConstraint _ lPat _ -> desugarLmlCase scrutineeVar (LmlCase ty lPat Nothing lExpr) +desugarLmlCase _scrutineeVar (LmlCase _ty (L _ _pat) (Just _guardExpr) lExpr) = do + expr <- desugarLLmlExpr lExpr + pure (DEFAULT, [], expr) + +desugarLmlCaseWithFallback :: Var -> LLmlCase LmlcTc -> CoreExpr -> MonadDesugar CoreMatchAlt +desugarLmlCaseWithFallback scrutineeVar (L _ (LmlCase ty (L _ pat) maybeGuard lExpr)) fallback = do + rhsCore <- desugarLLmlExpr lExpr + + case pat of + LmlPatAny _ -> do + finalRhs <- case maybeGuard of + Nothing -> pure rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + pure (DEFAULT, [], finalRhs) + LmlPatVar (FullName n, _) _ -> do + let rhsWithBinding = replaceVar (Id $ Name n) scrutineeVar rhsCore + finalRhs <- case maybeGuard of + Nothing -> pure rhsWithBinding + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + let guardWithBinding = replaceVar (Id $ Name n) scrutineeVar guardResult + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsWithBinding) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardWithBinding guardVar (trueAlt :| [falseAlt]) + pure (DEFAULT, [], finalRhs) + LmlPatConstant _ lit -> do + finalRhs <- case maybeGuard of + Nothing -> pure rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + pure (LitAlt $ desugarLmlLit lit, [], finalRhs) + LmlPatTuple _ lPat lPats -> do + (vars, wrappers) <- mapAndUnzipM desugarNestedPatHelper (lPat : toList lPats) + let pats = lPat : toList lPats + hasNesting = not $ all isSimpleVarOrWildcard pats + case (hasNesting, maybeGuard) of + (True, Just guardExpr) -> do + let applyWrappers rhs = foldr (\(var, wrapper) acc -> wrapper var acc) rhs (zip vars wrappers) + guardCheck <- do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + let finalRhs = applyWrappers guardCheck + pure (TupleAlt, vars, finalRhs) + _ -> do + let applyWrappers rhs = foldr (\(var, wrapper) acc -> wrapper var acc) rhs (zip vars wrappers) + finalRhs <- case maybeGuard of + Nothing -> pure $ applyWrappers rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], applyWrappers rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ applyWrappers (Match guardResult guardVar (trueAlt :| [falseAlt])) + pure (TupleAlt, vars, finalRhs) + LmlPatConstraint _ lPat _ -> + desugarLmlCaseWithFallback scrutineeVar (L (getLoc lPat) (LmlCase ty lPat maybeGuard lExpr)) fallback + LmlPatConstruct _ (L _ longident) maybeLPat -> + let constructorName = Name longident + in case maybeLPat of + Nothing -> do + finalRhs <- case maybeGuard of + Nothing -> pure rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + pure (DataAlt constructorName, [], finalRhs) + Just (L _ args) -> do + case args of + LmlPatVar (FullName n, _) _ -> do + finalRhs <- case maybeGuard of + Nothing -> pure rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + pure (DataAlt constructorName, [Id $ Name n], finalRhs) + LmlPatAny _ -> do + freshV <- freshVar + finalRhs <- case maybeGuard of + Nothing -> pure rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + pure (DataAlt constructorName, [freshV], finalRhs) + LmlPatTuple _ lPat lPats -> do + let pats = lPat : toList lPats + hasNesting = not $ all isSimpleVarOrWildcard pats + case (hasNesting, maybeGuard) of + (True, Just guardExpr) -> do + (vars, wrappers) <- mapAndUnzipM desugarNestedPatHelper pats + let applyWrappers rhs = foldr (\(var, wrapper) acc -> wrapper var acc) rhs (zip vars wrappers) + guardCheck <- do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + pure $ Match guardResult guardVar (trueAlt :| [falseAlt]) + let finalRhs = applyWrappers guardCheck + tupleVar <- freshVar + matchVar <- freshVar + let tupleAlt = (TupleAlt, vars, finalRhs) + tupleMatch = Match (Var tupleVar) matchVar (tupleAlt :| []) + pure (DataAlt constructorName, [tupleVar], tupleMatch) + _ -> do + (vars, wrappers) <- mapAndUnzipM desugarNestedPatHelper pats + let applyWrappers rhs = foldr (\(var, wrapper) acc -> wrapper var acc) rhs (zip vars wrappers) + finalRhs <- case maybeGuard of + Nothing -> + pure $ applyWrappers rhsCore + Just guardExpr -> do + guardResult <- desugarLLmlExpr guardExpr + guardVar <- freshVar + let guardCheckExpr = + let trueAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["true"]), [], applyWrappers rhsCore) + falseAlt = (DataAlt (Name $ mkLongident $ stdPrefix :| ["false"]), [], fallback) + in Match guardResult guardVar (trueAlt :| [falseAlt]) + pure $ applyWrappers guardCheckExpr + tupleVar <- freshVar + matchVar <- freshVar + let tupleAlt = (TupleAlt, vars, finalRhs) + tupleMatch = Match (Var tupleVar) matchVar (tupleAlt :| []) + pure (DataAlt constructorName, [tupleVar], tupleMatch) + _ -> do + let singleCase = L generatedSrcSpan (LmlCase ty (L generatedSrcSpan pat) maybeGuard lExpr) + alts <- compilePatternsWithBacktracking scrutineeVar (singleCase :| []) + pure $ NE.head alts + _ -> do + let singleCase = L generatedSrcSpan (LmlCase ty (L generatedSrcSpan pat) maybeGuard lExpr) + alts <- compilePatternsWithBacktracking scrutineeVar (singleCase :| []) + pure $ NE.head alts desugarLLmlPat :: LLmlPat LmlcTc -> MonadDesugar Var desugarLLmlPat (L _ pat) = desugarLmlPat pat @@ -95,7 +854,8 @@ desugarLmlPat :: LmlPat LmlcTc -> MonadDesugar Var desugarLmlPat = \case LmlPatVar (FullName n, _) _ -> pure $ Id $ Name n LmlPatConstraint _ lPat _ -> desugarLLmlPat lPat - _ -> error "FIXME: Only Var and Constraint patterns are currently supported." + LmlPatAny _ -> freshVar + _ -> error "FIXME: Only Var, Constraint and Any patterns are currently supported." desugarLLmlBindGroup :: LLmlBindGroup LmlcTc -> MonadDesugar (NonEmpty CoreBind) desugarLLmlBindGroup (L _ bindGroup) = desugarLmlBindGroup bindGroup @@ -148,13 +908,27 @@ replaceVarMatchAlt :: Var -> Var -> CoreMatchAlt -> CoreMatchAlt replaceVarMatchAlt oldVar newVar alt@(altCon, boundVars, expr) = if oldVar `elem` boundVars then alt else (altCon, boundVars, replaceVar oldVar newVar expr) -desugarLLmlDecl :: LLmlDecl LmlcTc -> MonadDesugar [CoreBind] -desugarLLmlDecl (L _ decl) = desugarLmlDecl decl +desugarLLmlDecl :: Maybe (LLongident LmlcTc) -> LLmlDecl LmlcTc -> MonadDesugar [CoreBind] +desugarLLmlDecl moduleName (L _ decl) = desugarLmlDecl moduleName decl -desugarLmlDecl :: LmlDecl LmlcTc -> MonadDesugar [CoreBind] -desugarLmlDecl = \case +desugarLmlDecl :: Maybe (LLongident LmlcTc) -> LmlDecl LmlcTc -> MonadDesugar [CoreBind] +desugarLmlDecl moduleName = \case ValD _ lBindGroup -> toList <$> desugarLLmlBindGroup lBindGroup + TyD _ tyDecls -> concat <$> mapM (desugarLTyDecl moduleName) (toList tyDecls) _ -> pure [] +desugarLTyDecl :: Maybe (LLongident LmlcTc) -> LTyDecl LmlcTc -> MonadDesugar [CoreBind] +desugarLTyDecl moduleName (L _ (DataDecl _ (L _ _typeName) _params conDecls)) = + mapM (desugarLConDeclToBind moduleName) conDecls +desugarLTyDecl _ _ = pure [] + +desugarLConDeclToBind :: Maybe (LLongident LmlcTc) -> LConDecl LmlcTc -> MonadDesugar CoreBind +desugarLConDeclToBind moduleName (L _ (ConDecl _ (L _ conName) _args)) = do + let qualifiedName = case moduleName of + Just (L _ (Longident modNameNE)) -> Longident $ modNameNE <> pure conName + Nothing -> mkLongident $ pure conName + conVar = Id $ Name qualifiedName + pure $ NonRec conVar (Var conVar) + desugarLmlModule :: LmlModule LmlcTc -> MonadDesugar [CoreBind] -desugarLmlModule (LmlModule _ _ lDecls) = concatMapM desugarLLmlDecl lDecls +desugarLmlModule (LmlModule _ moduleName lDecls) = concatMapM (desugarLLmlDecl moduleName) lDecls diff --git a/lamagraph-compiler/src/Lamagraph/Compiler/Eval.hs b/lamagraph-compiler/src/Lamagraph/Compiler/Eval.hs index 09904a3f..6b6716c1 100644 --- a/lamagraph-compiler/src/Lamagraph/Compiler/Eval.hs +++ b/lamagraph-compiler/src/Lamagraph/Compiler/Eval.hs @@ -13,7 +13,7 @@ import Lamagraph.Compiler.Typechecker.TcTypes data UnaryPrim = UPMinus | UPPrintInt deriving (Show) -data BinaryPrim = BPPlus | BPMinus | BPTimes | BPLess deriving (Show) +data BinaryPrim = BPPlus | BPMinus | BPTimes | BPGreater | BPLess | BPGreaterEq | BPLessEq deriving (Show) data Value = VInt Int @@ -103,9 +103,18 @@ evalBinaryPrim :: (MonadEval m) => BinaryPrim -> Value -> Value -> m Value evalBinaryPrim BPPlus (VInt arg1) (VInt arg2) = pure $ VInt $ arg1 + arg2 evalBinaryPrim BPMinus (VInt arg1) (VInt arg2) = pure $ VInt $ arg1 - arg2 evalBinaryPrim BPTimes (VInt arg1) (VInt arg2) = pure $ VInt $ arg1 * arg2 +evalBinaryPrim BPGreater (VInt arg1) (VInt arg2) = + let val = if arg1 > arg2 then "true" else "false" + in pure $ VAdt (Name $ mkLongident $ stdPrefix :| [val]) [] evalBinaryPrim BPLess (VInt arg1) (VInt arg2) = let val = if arg1 < arg2 then "true" else "false" in pure $ VAdt (Name $ mkLongident $ stdPrefix :| [val]) [] +evalBinaryPrim BPGreaterEq (VInt arg1) (VInt arg2) = + let val = if arg1 >= arg2 then "true" else "false" + in pure $ VAdt (Name $ mkLongident $ stdPrefix :| [val]) [] +evalBinaryPrim BPLessEq (VInt arg1) (VInt arg2) = + let val = if arg1 <= arg2 then "true" else "false" + in pure $ VAdt (Name $ mkLongident $ stdPrefix :| [val]) [] evalBinaryPrim prim arg1 arg2 = throwIO $ EInvalidBinaryApply prim arg1 arg2 {- | I think this is a bad code, because it can force pattern-matching in weird places @@ -161,16 +170,22 @@ matchAlts eEnv val = \case evalCoreBind :: (MonadEval m) => EvalEnv -> CoreBind -> m EvalEnv evalCoreBind eEnv = \case NonRec var expr -> do - value <- evalCoreExpr eEnv expr + value <- case expr of + Var var' | var == var' -> + case var of + Id (Name (Longident ne)) -> + pure $ VAdt (Name (Longident ne)) [] + _ -> evalCoreExpr eEnv expr pure $ coerce $ HashMap.insert var value (coerce eEnv) - Rec (bind :| []) -> - let (funVar, lamVar, lamExpr) = case bind of - (var, Lam lamVar' lamExpr') -> (var, lamVar', lamExpr') - _ -> impureThrow ENonLambdaUnderLetRec - recEnv = coerce $ HashMap.insert funVar (VClosure lamVar lamExpr recEnv) (coerce eEnv) - value = VClosure lamVar lamExpr recEnv - in pure $ coerce $ HashMap.insert funVar value (coerce eEnv) - Rec (_ :| _) -> throwIO EManyLetRecs + Rec binds -> + let extractLambda (var, Lam lamVar' lamExpr') = (var, lamVar', lamExpr') + extractLambda _ = impureThrow ENonLambdaUnderLetRec + lamInfos = fmap extractLambda binds + buildRecEnv :: EvalEnv + buildRecEnv = coerce $ foldr insertClosure (coerce eEnv) lamInfos + where + insertClosure (funVar, lamVar, lamExpr) = HashMap.insert funVar (VClosure lamVar lamExpr buildRecEnv) + in pure buildRecEnv evalCoreBinds :: (MonadEval m) => EvalEnv -> [CoreBind] -> m EvalEnv evalCoreBinds = foldlM evalCoreBind @@ -183,11 +198,16 @@ defEvalEnv = , (Id $ Name $ mkLongident $ stdPrefix :| ["+"], VBinaryPrim1 BPPlus) , (Id $ Name $ mkLongident $ stdPrefix :| ["-"], VBinaryPrim1 BPMinus) , (Id $ Name $ mkLongident $ stdPrefix :| ["*"], VBinaryPrim1 BPTimes) + , (Id $ Name $ mkLongident $ stdPrefix :| [">"], VBinaryPrim1 BPGreater) , (Id $ Name $ mkLongident $ stdPrefix :| ["<"], VBinaryPrim1 BPLess) + , (Id $ Name $ mkLongident $ stdPrefix :| [">="], VBinaryPrim1 BPGreaterEq) + , (Id $ Name $ mkLongident $ stdPrefix :| ["<="], VBinaryPrim1 BPLessEq) , (Id $ Name $ mkLongident $ stdPrefix :| ["[]"], VAdt (Name $ mkLongident $ stdPrefix :| ["[]"]) []) , (Id $ Name $ mkLongident $ stdPrefix :| ["::"], VAdt (Name $ mkLongident $ stdPrefix :| ["::"]) []) , (Id $ Name $ mkLongident $ stdPrefix :| ["Some"], VAdt (Name $ mkLongident $ stdPrefix :| ["Some"]) []) , (Id $ Name $ mkLongident $ stdPrefix :| ["None"], VAdt (Name $ mkLongident $ stdPrefix :| ["None"]) []) + , (Id $ Name $ mkLongident $ stdPrefix :| ["true"], VAdt (Name $ mkLongident $ stdPrefix :| ["true"]) []) + , (Id $ Name $ mkLongident $ stdPrefix :| ["false"], VAdt (Name $ mkLongident $ stdPrefix :| ["false"]) []) , (Id $ Name $ mkLongident $ stdPrefix :| ["print_int"], VUnaryPrim UPPrintInt) ] diff --git a/lamagraph-compiler/src/Lamagraph/Compiler/Typechecker/DefaultEnv.hs b/lamagraph-compiler/src/Lamagraph/Compiler/Typechecker/DefaultEnv.hs index 020246f2..fc02df9a 100644 --- a/lamagraph-compiler/src/Lamagraph/Compiler/Typechecker/DefaultEnv.hs +++ b/lamagraph-compiler/src/Lamagraph/Compiler/Typechecker/DefaultEnv.hs @@ -69,8 +69,8 @@ defaultEnv = TyEnv env , (Name $ mkLongident $ stdPrefix :| ["*"], Forall [] $ tyInt `TArrow` tyInt `TArrow` tyInt) , (Name $ mkLongident $ stdPrefix :| ["/"], Forall [] $ tyInt `TArrow` tyInt `TArrow` tyInt) , (Name $ mkLongident $ stdPrefix :| [">"], Forall [] $ tyInt `TArrow` tyInt `TArrow` tyBool) - , (Name $ mkLongident $ stdPrefix :| [">="], Forall [] $ tyInt `TArrow` tyInt `TArrow` tyBool) , (Name $ mkLongident $ stdPrefix :| ["<"], Forall [] $ tyInt `TArrow` tyInt `TArrow` tyBool) + , (Name $ mkLongident $ stdPrefix :| [">="], Forall [] $ tyInt `TArrow` tyInt `TArrow` tyBool) , (Name $ mkLongident $ stdPrefix :| ["<="], Forall [] $ tyInt `TArrow` tyInt `TArrow` tyBool) , (Name $ mkLongident $ stdPrefix :| ["[]"], Forall [Name $ mkLongident $ pure "a"] tyList) , diff --git a/lamagraph-compiler/test/golden/core/core/Counter.lml.core b/lamagraph-compiler/test/golden/core/core/Counter.lml.core new file mode 100644 index 00000000..9af74105 --- /dev/null +++ b/lamagraph-compiler/test/golden/core/core/Counter.lml.core @@ -0,0 +1,90 @@ +let Counter.Zero = Counter.Zero +let Counter.One = Counter.One +let Counter.Two = Counter.Two +let Counter.Three = Counter.Three +let Counter.Four = Counter.Four +let Counter.Five = Counter.Five +let Counter.Positive = Counter.Positive +let Counter.Zegative = Counter.Zegative +let Counter.Negative = Counter.Negative +let Counter.Error = Counter.Error +let Counter.sum_multi = fun Counter.x -> + match Counter.x as t#a with (Counter.Zero, [], 0) + | (Counter.One, [Counter.a], Counter.a) + | ( Counter.Two + , [Counter.a, Counter.b] + , (#std.+ Counter.a) Counter.b ) + | ( Counter.Three + , [Counter.a, Counter.b, Counter.c] + , (#std.+ Counter.a) ((#std.+ Counter.b) Counter.c) ) + | ( Counter.Four + , [Counter.a, Counter.b, Counter.c, Counter.d] + , (#std.+ Counter.a) ((#std.+ Counter.b) ((#std.+ Counter.c) Counter.d)) ) + | ( Counter.Five + , [ Counter.a + , Counter.b + , Counter.c + , Counter.d + , Counter.e ] + , (#std.+ Counter.a) ((#std.+ Counter.b) ((#std.+ Counter.c) ((#std.+ Counter.d) Counter.e))) ) +let Counter.one_sign = fun Counter.x -> + match Counter.x as t#b with ( Counter.One + , [Counter.x] + , match (#std.> Counter.x) 0 as t#e with ( #std.true + , [] + , Counter.Positive ) + | ( #std.false + , [] + , match t#b as t#b with ( Counter.One + , [Counter.x] + , match (#std.< Counter.x) 0 as t#d with ( #std.true + , [] + , Counter.Negative ) + | ( #std.false + , [] + , match t#b as t#b with ( Counter.One + , [t#c] + , Counter.Zegative ) + | (DEFAULT, [], Counter.Error) ) ) + | (Counter.One, [t#c], Counter.Zegative) + | (DEFAULT, [], Counter.Error) ) ) + | ( Counter.One + , [Counter.x] + , match (#std.< Counter.x) 0 as t#d with ( #std.true + , [] + , Counter.Negative ) + | ( #std.false + , [] + , match t#b as t#b with ( Counter.One + , [t#c] + , Counter.Zegative ) + | (DEFAULT, [], Counter.Error) ) ) + | (Counter.One, [t#c], Counter.Zegative) + | (DEFAULT, [], Counter.Error) +let Counter.signum = fun Counter.x -> + match Counter.x as t#f with (Counter.Positive, [], 1) + | (Counter.Negative, [], -1) + | (DEFAULT, [], 0) +let Counter.signed = fun Counter.x -> + match Counter.x as t#g with (Counter.Positive, [], 1) + | (Counter.Negative, [], 1) + | (Counter.Zegative, [], 0) + | (Counter.Error, [], 0) +let Counter.zero = Counter.Zero +let Counter.one = Counter.One 1 +let Counter.minus_one = Counter.One -10 +let Counter.two = Counter.Two ((1), (2)) +let Counter.three = Counter.Three ((2), (1), (3)) +let Counter.four = Counter.Four ((1), (4), (3), (2)) +let Counter.five = Counter.Five ((5), (1), (2), (4), (3)) +let t#h = #std.print_int (Counter.sum_multi Counter.zero) +let t#i = #std.print_int (Counter.sum_multi Counter.one) +let t#j = #std.print_int (Counter.sum_multi Counter.two) +let t#k = #std.print_int (Counter.sum_multi Counter.three) +let t#l = #std.print_int (Counter.sum_multi Counter.four) +let t#m = #std.print_int (Counter.sum_multi Counter.five) +let t#n = #std.print_int (Counter.signum (Counter.one_sign Counter.one)) +let t#o = #std.print_int (Counter.signum (Counter.one_sign Counter.minus_one)) +let t#p = #std.print_int (Counter.signum (Counter.one_sign Counter.three)) +let t#q = #std.print_int (Counter.signed (Counter.one_sign Counter.zero)) +let t#r = #std.print_int ((#std.+ (Counter.signed (Counter.one_sign Counter.one))) (Counter.signed (Counter.one_sign Counter.minus_one))) \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/core/core/Forest.lml.core b/lamagraph-compiler/test/golden/core/core/Forest.lml.core new file mode 100644 index 00000000..22e0fb99 --- /dev/null +++ b/lamagraph-compiler/test/golden/core/core/Forest.lml.core @@ -0,0 +1,21 @@ +let Forest.Leaf = Forest.Leaf +let Forest.Node = Forest.Node +let Forest.Nil = Forest.Nil +let Forest.Cons = Forest.Cons +let rec Forest.tree_sum = fun Forest.t -> + match Forest.t as t#a with ( Forest.Leaf + , [Forest.v] + , Forest.v ) + | ( Forest.Node + , [Forest.f] + , Forest.forest_sum Forest.f ) +and +Forest.forest_sum = fun Forest.f -> match Forest.f as t#b with ( Forest.Nil + , [] + , 0 ) + | ( Forest.Cons + , [Forest.t, Forest.rest] + , (#std.+ (Forest.tree_sum Forest.t)) (Forest.forest_sum Forest.rest) ) +let t#c = #std.print_int (Forest.forest_sum (Forest.Cons ((Forest.Leaf 10), + (Forest.Cons ((Forest.Node (Forest.Cons ((Forest.Leaf 20), + (Forest.Nil)))), (Forest.Nil)))))) \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/core/core/Insanity.lml.core b/lamagraph-compiler/test/golden/core/core/Insanity.lml.core new file mode 100644 index 00000000..d5505755 --- /dev/null +++ b/lamagraph-compiler/test/golden/core/core/Insanity.lml.core @@ -0,0 +1,63 @@ +let Insanity.F = Insanity.F +let Insanity.S = Insanity.S +let Insanity.T = Insanity.T +let Insanity.Tempty = Insanity.Tempty +let rec Insanity.first_sum = fun Insanity.a -> + match Insanity.a as t#a with ( Insanity.F + , [Insanity.x, Insanity.b] + , (#std.+ Insanity.x) (Insanity.second_sum Insanity.b) ) +and +Insanity.second_sum = fun Insanity.b -> + match Insanity.b as t#b with ( Insanity.S + , [Insanity.x, Insanity.c] + , (#std.+ Insanity.x) (Insanity.third_sum Insanity.c) ) +and +Insanity.third_sum = fun Insanity.c -> + match Insanity.c as t#c with (Insanity.Tempty, [], 0) + | ( Insanity.T + , [Insanity.x, Insanity.a] + , (#std.+ Insanity.x) (Insanity.first_sum Insanity.a) ) +let Insanity.result = #std.print_int (Insanity.first_sum (Insanity.F ((1), + (Insanity.S ((2), (Insanity.T ((3), (Insanity.F ((4), + (Insanity.S ((5), (Insanity.Tempty)))))))))))) +let Insanity.classify_num = fun Insanity.n -> match Insanity.n as t#d with ( 0 + , [] + , 100 ) + | (1, [], 101) + | (2, [], 102) + | (5, [], 105) + | (DEFAULT, [], 999) +let Insanity.negate = fun Insanity.b -> match Insanity.b as t#e with ( #std.true + , [] + , #std.false ) + | (#std.false, [], #std.true) +let Insanity.to_int = fun Insanity.b -> match Insanity.b as t#f with ( #std.true + , [] + , 1 ) + | (#std.false, [], 0) +let Insanity.bool_and = fun Insanity.a -> fun Insanity.b -> + match Insanity.a as t#g with ( #std.true + , [] + , match Insanity.b as t#h with ( #std.true + , [] + , #std.true ) + | (#std.false, [], #std.false) ) + | (#std.false, [], #std.false) +let Insanity.sign = fun Insanity.n -> match Insanity.n as t#i with (0, [], 0) + | ( DEFAULT + , [] + , match (#std.> t#i) 0 as t#j with ( #std.true + , [] + , 1 ) + | (#std.false, [], -1) ) +let t#k = #std.print_int (Insanity.classify_num 0) +let t#l = #std.print_int (Insanity.classify_num 1) +let t#m = #std.print_int (Insanity.classify_num 5) +let t#n = #std.print_int (Insanity.classify_num 42) +let t#o = #std.print_int (Insanity.to_int (Insanity.negate #std.true)) +let t#p = #std.print_int (Insanity.to_int (Insanity.negate #std.false)) +let t#q = #std.print_int (Insanity.to_int ((Insanity.bool_and #std.true) #std.true)) +let t#r = #std.print_int (Insanity.to_int ((Insanity.bool_and #std.true) #std.false)) +let t#s = #std.print_int (Insanity.sign 0) +let t#t = #std.print_int (Insanity.sign 42) +let t#u = #std.print_int (Insanity.sign -10) \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/core/core/Option.lml.core b/lamagraph-compiler/test/golden/core/core/Option.lml.core new file mode 100644 index 00000000..9667f8df --- /dev/null +++ b/lamagraph-compiler/test/golden/core/core/Option.lml.core @@ -0,0 +1,47 @@ +let Option.None = Option.None +let Option.Some = Option.Some +let Option.map = fun Option.f -> fun Option.opt -> + match Option.opt as t#a with ( Option.Some + , [Option.x] + , Option.Some (Option.f Option.x) ) + | (Option.None, [], Option.None) +let Option.mapOrDefault = fun Option.f -> fun Option.default -> + fun Option.opt -> + match Option.opt as t#b with ( Option.Some + , [Option.x] + , Option.f Option.x ) + | (Option.None, [], Option.default) +let Option.increment = fun Option.x -> (#std.+ Option.x) 1 +let Option.double = fun Option.x -> (#std.* Option.x) 2 +let Option.f = fun Option.opt -> + (Option.map Option.double) ((Option.map Option.increment) Option.opt) +let rec Option.count_somes = fun Option.l -> + match Option.l as t#c with (#std.[], [], 0) + | ( #std.:: + , [Option.hd, Option.tl] + , let Option.count_tl = Option.count_somes Option.tl + in match Option.hd as t#d with ( Option.None + , [] + , Option.count_tl ) + | ( Option.Some + , [t#e] + , (#std.+ 1) Option.count_tl ) ) +let rec Option.sum_list_of_options = fun Option.l -> + match Option.l as t#f with (#std.[], [], 0) + | ( #std.:: + , [Option.hd, Option.tl] + , let Option.sum_tl = Option.sum_list_of_options Option.tl + in match Option.hd as t#g with ( Option.None + , [] + , Option.sum_tl ) + | ( Option.Some + , [Option.v] + , (#std.+ Option.v) Option.sum_tl ) ) +let Option.l_of_opts = #std.:: ((Option.Some 1), (#std.:: ((Option.None), + (#std.:: ((Option.Some 3), (#std.:: ((Option.Some 5), + (#std.[])))))))) +let t#h = #std.print_int (((Option.mapOrDefault Option.increment) 0) (Option.f (Option.Some 5))) +let t#i = #std.print_int (((Option.mapOrDefault Option.double) 0) (Option.Some 42)) +let t#j = #std.print_int (((Option.mapOrDefault Option.double) 0) Option.None) +let Option.result1 = #std.print_int (Option.count_somes Option.l_of_opts) +let Option.result2 = #std.print_int (Option.sum_list_of_options Option.l_of_opts) \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/core/core/Range.lml.core b/lamagraph-compiler/test/golden/core/core/Range.lml.core new file mode 100644 index 00000000..4384441b --- /dev/null +++ b/lamagraph-compiler/test/golden/core/core/Range.lml.core @@ -0,0 +1,49 @@ +let rec Range.range = fun Range.n -> + match (#std.< Range.n) 1 as t#a with ( #std.true + , [] + , #std.[] ) + | ( #std.false + , [] + , let Range.tl = Range.range ((#std.- Range.n) 1) + in #std.:: ((Range.n), (Range.tl)) ) +let rec Range.sum_list = fun Range.l -> match Range.l as t#b with ( #std.[] + , [] + , 0 ) + | ( #std.:: + , [Range.hd, Range.tl] + , (#std.+ Range.hd) (Range.sum_list Range.tl) ) +let rec Range.length = fun Range.l -> match Range.l as t#c with (#std.[], [], 0) + | ( #std.:: + , [t#d, Range.tl] + , (#std.+ 1) (Range.length Range.tl) ) +let rec Range.map = fun Range.f -> fun Range.l -> + match Range.l as t#e with ( #std.:: + , [Range.hd, Range.tl] + , #std.:: ((Range.f Range.hd), + ((Range.map Range.f) Range.tl)) ) + | (#std.[], [], #std.[]) +let Range.increment = fun Range.x -> (#std.+ Range.x) 1 +let Range.head_of_head = fun Range.ll -> match Range.ll as t#f with ( #std.[] + , [] + , 0 ) + | ( #std.:: + , [Range.l, t#i] + , match Range.l as t#g with ( #std.[] + , [] + , 1 ) + | ( #std.:: + , [Range.hd, t#h] + , Range.hd ) ) +let Range.r = Range.range 100 +let Range.l = #std.:: ((1), (#std.:: ((2), (#std.:: ((3), (#std.[])))))) +let Range.l' = let Range.list_increment = Range.map Range.increment + in Range.list_increment Range.l +let Range.ll = #std.:: ((#std.:: ((42), (#std.:: ((43), (#std.[]))))), + (#std.:: ((#std.:: ((44), (#std.[]))), (#std.[])))) +let Range.empty_ll = #std.:: ((#std.[]), (#std.[])) +let t#j = #std.print_int (Range.sum_list Range.r) +let t#k = #std.print_int (Range.length Range.r) +let t#l = #std.print_int (Range.length Range.l) +let t#m = #std.print_int (Range.sum_list Range.l') +let t#n = #std.print_int (Range.head_of_head Range.ll) +let t#o = #std.print_int (Range.head_of_head Range.empty_ll) \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/core/core/Tree.lml.core b/lamagraph-compiler/test/golden/core/core/Tree.lml.core new file mode 100644 index 00000000..15edb17f --- /dev/null +++ b/lamagraph-compiler/test/golden/core/core/Tree.lml.core @@ -0,0 +1,14 @@ +let Tree.Leaf = Tree.Leaf +let Tree.Node = Tree.Node +let rec Tree.sum_tree = fun Tree.t -> match Tree.t as t#a with ( Tree.Leaf + , [Tree.v] + , Tree.v ) + | ( Tree.Node + , [Tree.v, Tree.left, Tree.right] + , (#std.+ Tree.v) ((#std.+ (Tree.sum_tree Tree.left)) (Tree.sum_tree Tree.right)) ) +let t#b = #std.print_int (Tree.sum_tree (Tree.Node ((10), (Tree.Node ((5), + (Tree.Leaf 0), (Tree.Leaf 0))), (Tree.Node ((15), (Tree.Leaf 0), + (Tree.Leaf 0)))))) +let t#c = #std.print_int (Tree.sum_tree (Tree.Node ((4), (Tree.Node ((2), + (Tree.Leaf 1), (Tree.Leaf 3))), (Tree.Node ((6), (Tree.Leaf 5), + (Tree.Leaf 7)))))) \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/core/core/Tuples.lml.core b/lamagraph-compiler/test/golden/core/core/Tuples.lml.core new file mode 100644 index 00000000..8c3edce4 --- /dev/null +++ b/lamagraph-compiler/test/golden/core/core/Tuples.lml.core @@ -0,0 +1,29 @@ +let Tuples.Pair = Tuples.Pair +let Tuples.Triple = Tuples.Triple +let Tuples.fst = fun Tuples.p -> match Tuples.p as t#a with ( Tuples.Pair + , [Tuples.x, t#b] + , Tuples.x ) +let Tuples.snd = fun Tuples.p -> match Tuples.p as t#c with ( Tuples.Pair + , [t#d, Tuples.y] + , Tuples.y ) +let Tuples.first_of_int_triple = fun Tuples.t -> + match Tuples.t as t#e with ( Tuples.Triple + , [Tuples.x, t#f, t#g] + , Tuples.x ) +let Tuples.second_of_int_triple = fun Tuples.t -> + match Tuples.t as t#h with ( Tuples.Triple + , [t#i, Tuples.y, t#j] + , Tuples.y ) +let Tuples.sum_of_first_and_third_of_int_triple = fun Tuples.t -> + match Tuples.t as t#k with ( Tuples.Triple + , [Tuples.x, t#l, Tuples.z] + , (#std.+ Tuples.x) Tuples.z ) +let Tuples.swap = fun Tuples.p -> match Tuples.p as t#m with ( Tuples.Pair + , [Tuples.x, Tuples.y] + , Tuples.Pair ((Tuples.y), (Tuples.x)) ) +let Tuples.t = Tuples.Triple ((1), (2), (3)) +let t#n = #std.print_int (Tuples.fst (Tuples.swap (Tuples.Pair ((1), (2))))) +let t#o = #std.print_int (Tuples.fst (Tuples.Pair ((42), (#std.true)))) +let t#p = #std.print_int (Tuples.snd (Tuples.Pair ((#std.false), (100)))) +let t#q = #std.print_int (Tuples.sum_of_first_and_third_of_int_triple Tuples.t) +let t#r = #std.print_int (Tuples.second_of_int_triple Tuples.t) \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/core/source/Counter.lml b/lamagraph-compiler/test/golden/core/source/Counter.lml new file mode 100644 index 00000000..e0d158a7 --- /dev/null +++ b/lamagraph-compiler/test/golden/core/source/Counter.lml @@ -0,0 +1,60 @@ +module Counter + +type counter = + | Zero + | One of int + | Two of int * int + | Three of int * int * int + | Four of int * int * int * int + | Five of int * int * int * int * int + +type sign = + | Positive + | Zegative + | Negative + | Error + +let sum_multi x = match x with + | Zero -> 0 + | One a -> a + | Two (a, b) -> a + b + | Three (a, b, c) -> a + b + c + | Four (a, b, c, d) -> a + b + c + d + | Five (a, b, c, d, e) -> a + b + c + d + e + +let one_sign x = match x with + | One x when x > 0 -> Positive + | One x when x < 0 -> Negative + | One _ -> Zegative + | _ -> Error + +let signum x = match x with + | Positive -> 1 + | Negative -> -1 + | _ -> 0 + +let signed x = match x with + | Positive | Negative -> 1 + | Zegative | Error -> 0 + +let zero = Zero +let one = One 1 +let minus_one = One (-10) +let two = Two (1, 2) +let three = Three (2, 1, 3) +let four = Four (1, 4, 3, 2) +let five = Five (5, 1, 2, 4, 3) + +let _ = print_int (sum_multi zero) +let _ = print_int (sum_multi one) +let _ = print_int (sum_multi two) +let _ = print_int (sum_multi three) +let _ = print_int (sum_multi four) +let _ = print_int (sum_multi five) + +let _ = print_int (signum (one_sign one)) +let _ = print_int (signum (one_sign minus_one)) +let _ = print_int (signum (one_sign three)) + +let _ = print_int (signed (one_sign zero)) +let _ = print_int ((signed (one_sign one)) + (signed (one_sign minus_one))) diff --git a/lamagraph-compiler/test/golden/core/source/Forest.lml b/lamagraph-compiler/test/golden/core/source/Forest.lml new file mode 100644 index 00000000..49b31fef --- /dev/null +++ b/lamagraph-compiler/test/golden/core/source/Forest.lml @@ -0,0 +1,13 @@ +module Forest + +type 'a tree = Leaf of 'a | Node of 'a forest +and 'a forest = Nil | Cons of 'a tree * 'a forest + +let rec tree_sum t = match t with + | Leaf v -> v + | Node f -> forest_sum f +and forest_sum f = match f with + | Nil -> 0 + | Cons (t, rest) -> (tree_sum t) + (forest_sum rest) + +let _ = print_int (forest_sum (Cons ((Leaf 10), (Cons ((Node (Cons ((Leaf 20), Nil))), Nil))))) diff --git a/lamagraph-compiler/test/golden/core/source/Insanity.lml b/lamagraph-compiler/test/golden/core/source/Insanity.lml new file mode 100644 index 00000000..44e5b250 --- /dev/null +++ b/lamagraph-compiler/test/golden/core/source/Insanity.lml @@ -0,0 +1,54 @@ +module Insanity + +type 'a first = F of 'a * 'a second +and 'a second = S of 'a * 'a third +and 'a third = T of 'a * 'a first | Tempty + +let rec first_sum a = match a with + | F (x, b) -> x + (second_sum b) +and second_sum b = match b with + | S (x, c) -> x + (third_sum c) +and third_sum c = match c with + | Tempty -> 0 + | T (x, a) -> x + (first_sum a) + +let result = print_int (first_sum (F (1, (S (2, (T (3, (F (4, (S (5, Tempty))))))))))) + +let classify_num n = match n with + | 0 -> 100 + | 1 -> 101 + | 2 -> 102 + | 5 -> 105 + | _ -> 999 + +let negate b = match b with + | true -> false + | false -> true + +let to_int b = match b with + | true -> 1 + | false -> 0 + +let bool_and a b = match a with + | true -> (match b with + | true -> true + | false -> false) + | false -> false + +let sign n = match n with + | 0 -> 0 + | n -> match n > 0 with + | true -> 1 + | false -> -1 + +let _ = print_int (classify_num 0) +let _ = print_int (classify_num 1) +let _ = print_int (classify_num 5) +let _ = print_int (classify_num 42) +let _ = print_int (to_int (negate true)) +let _ = print_int (to_int (negate false)) +let _ = print_int (to_int (bool_and true true)) +let _ = print_int (to_int (bool_and true false)) +let _ = print_int (sign 0) +let _ = print_int (sign 42) +let _ = print_int (sign (-10)) diff --git a/lamagraph-compiler/test/golden/core/source/Option.lml b/lamagraph-compiler/test/golden/core/source/Option.lml new file mode 100644 index 00000000..f7fe424e --- /dev/null +++ b/lamagraph-compiler/test/golden/core/source/Option.lml @@ -0,0 +1,49 @@ +module Option + +type 'a option = + | None + | Some of 'a + +let map f opt = + match opt with + | Some x -> Some (f x) + | None -> None + +let mapOrDefault f default opt = + match opt with + | Some x -> f x + | None -> default + +let increment x = x + 1 +let double x = x * 2 + +let f opt = map double (map increment opt) + +type 'a list_of_options = 'a option list + +type 'a option_of_list = 'a list option + +let rec count_somes l = match l with + | [] -> 0 + | hd :: tl -> + let count_tl = count_somes tl in + match hd with + | None -> count_tl + | Some _ -> 1 + count_tl + +let rec sum_list_of_options l = match l with + | [] -> 0 + | hd :: tl -> + let sum_tl = sum_list_of_options tl in + match hd with + | None -> sum_tl + | Some v -> v + sum_tl + +let l_of_opts = (Some 1) :: (None :: ((Some 3) :: ((Some 5) :: []))) + +let _ = print_int (mapOrDefault increment 0 (f (Some 5))) +let _ = print_int (mapOrDefault double 0 (Some 42)) +let _ = print_int (mapOrDefault double 0 None) + +let result1 = print_int (count_somes l_of_opts) +let result2 = print_int (sum_list_of_options l_of_opts) diff --git a/lamagraph-compiler/test/golden/core/source/Range.lml b/lamagraph-compiler/test/golden/core/source/Range.lml new file mode 100644 index 00000000..b992382a --- /dev/null +++ b/lamagraph-compiler/test/golden/core/source/Range.lml @@ -0,0 +1,44 @@ +module Range + +let rec range n = + if n < 1 then [] + else + let tl = range (n - 1) in + n :: tl + +let rec sum_list l = match l with + | [] -> 0 + | hd :: tl -> hd + (sum_list tl) + +let rec length l = match l with + | [] -> 0 + | _ :: tl -> 1 + (length tl) + +let rec map f l = match l with + | hd :: tl -> (f hd) :: (map f tl) + | [] -> [] + +let increment x = x + 1 + +let head_of_head ll = match ll with + | [] -> 0 + | l :: _ -> + match l with + | [] -> 1 + | hd :: _ -> hd + +let r = range 100 + +let l = 1 :: (2 :: (3 :: [])) +let l' = let list_increment = map increment in list_increment l + +let ll = (42 :: 43 :: []) :: (44 :: []) :: [] +let empty_ll = [] :: [] + +let _ = print_int (sum_list r) +let _ = print_int (length r) +let _ = print_int (length l) +let _ = print_int (sum_list l') + +let _ = print_int (head_of_head ll) +let _ = print_int (head_of_head empty_ll) diff --git a/lamagraph-compiler/test/golden/core/source/Tree.lml b/lamagraph-compiler/test/golden/core/source/Tree.lml new file mode 100644 index 00000000..638b5341 --- /dev/null +++ b/lamagraph-compiler/test/golden/core/source/Tree.lml @@ -0,0 +1,10 @@ +module Tree + +type 'a tree = Leaf of 'a | Node of 'a * 'a tree * 'a tree + +let rec sum_tree t = match t with + | Leaf v -> v + | Node (v, left, right) -> v + (sum_tree left) + (sum_tree right) + +let _ = print_int (sum_tree (Node (10, (Node (5, (Leaf 0), (Leaf 0))), (Node (15, (Leaf 0), (Leaf 0)))))) +let _ = print_int (sum_tree (Node (4, (Node (2, (Leaf 1), (Leaf 3))), (Node (6, (Leaf 5), (Leaf 7)))))) diff --git a/lamagraph-compiler/test/golden/core/source/Tuples.lml b/lamagraph-compiler/test/golden/core/source/Tuples.lml new file mode 100644 index 00000000..be034b47 --- /dev/null +++ b/lamagraph-compiler/test/golden/core/source/Tuples.lml @@ -0,0 +1,31 @@ +module Tuples + +type ('a, 'b) pair = Pair of 'a * 'b +type ('a, 'b, 'c) triple = Triple of 'a * 'b * 'c + +let fst p = match p with + | Pair (x, _) -> x + +let snd p = match p with + | Pair (_, y) -> y + +let first_of_int_triple t = match t with + | Triple (x, _, _) -> x + +let second_of_int_triple t = match t with + | Triple (_, y, _) -> y + +let sum_of_first_and_third_of_int_triple t = match t with + | Triple (x, _, z) -> x + z + +let swap p = match p with + | Pair (x, y) -> Pair (y, x) + +let t = Triple (1, 2, 3) + +let _ = print_int (fst (swap (Pair (1, 2)))) +let _ = print_int (fst (Pair (42, true))) +let _ = print_int (snd (Pair (false, 100))) + +let _ = print_int (sum_of_first_and_third_of_int_triple t) +let _ = print_int (second_of_int_triple t) diff --git a/lamagraph-compiler/test/golden/eval/output/Counter.lml.out b/lamagraph-compiler/test/golden/eval/output/Counter.lml.out new file mode 100644 index 00000000..16cffe8c --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/output/Counter.lml.out @@ -0,0 +1 @@ +013610151-1002 \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/eval/output/Forest.lml.out b/lamagraph-compiler/test/golden/eval/output/Forest.lml.out new file mode 100644 index 00000000..8580e7b6 --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/output/Forest.lml.out @@ -0,0 +1 @@ +30 \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/eval/output/Insanity.lml.out b/lamagraph-compiler/test/golden/eval/output/Insanity.lml.out new file mode 100644 index 00000000..441decf3 --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/output/Insanity.lml.out @@ -0,0 +1 @@ +15100101105999011001-1 \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/eval/output/Option.lml.out b/lamagraph-compiler/test/golden/eval/output/Option.lml.out new file mode 100644 index 00000000..40adadf8 --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/output/Option.lml.out @@ -0,0 +1 @@ +1384039 \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/eval/output/Range.lml.out b/lamagraph-compiler/test/golden/eval/output/Range.lml.out new file mode 100644 index 00000000..ca8fbc61 --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/output/Range.lml.out @@ -0,0 +1 @@ +505010039421 \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/eval/output/Tree.lml.out b/lamagraph-compiler/test/golden/eval/output/Tree.lml.out new file mode 100644 index 00000000..b19e196a --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/output/Tree.lml.out @@ -0,0 +1 @@ +3028 \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/eval/output/Tuples.lml.out b/lamagraph-compiler/test/golden/eval/output/Tuples.lml.out new file mode 100644 index 00000000..e628a4f4 --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/output/Tuples.lml.out @@ -0,0 +1 @@ +24210042 \ No newline at end of file diff --git a/lamagraph-compiler/test/golden/eval/source/Counter.lml b/lamagraph-compiler/test/golden/eval/source/Counter.lml new file mode 100644 index 00000000..e0d158a7 --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/source/Counter.lml @@ -0,0 +1,60 @@ +module Counter + +type counter = + | Zero + | One of int + | Two of int * int + | Three of int * int * int + | Four of int * int * int * int + | Five of int * int * int * int * int + +type sign = + | Positive + | Zegative + | Negative + | Error + +let sum_multi x = match x with + | Zero -> 0 + | One a -> a + | Two (a, b) -> a + b + | Three (a, b, c) -> a + b + c + | Four (a, b, c, d) -> a + b + c + d + | Five (a, b, c, d, e) -> a + b + c + d + e + +let one_sign x = match x with + | One x when x > 0 -> Positive + | One x when x < 0 -> Negative + | One _ -> Zegative + | _ -> Error + +let signum x = match x with + | Positive -> 1 + | Negative -> -1 + | _ -> 0 + +let signed x = match x with + | Positive | Negative -> 1 + | Zegative | Error -> 0 + +let zero = Zero +let one = One 1 +let minus_one = One (-10) +let two = Two (1, 2) +let three = Three (2, 1, 3) +let four = Four (1, 4, 3, 2) +let five = Five (5, 1, 2, 4, 3) + +let _ = print_int (sum_multi zero) +let _ = print_int (sum_multi one) +let _ = print_int (sum_multi two) +let _ = print_int (sum_multi three) +let _ = print_int (sum_multi four) +let _ = print_int (sum_multi five) + +let _ = print_int (signum (one_sign one)) +let _ = print_int (signum (one_sign minus_one)) +let _ = print_int (signum (one_sign three)) + +let _ = print_int (signed (one_sign zero)) +let _ = print_int ((signed (one_sign one)) + (signed (one_sign minus_one))) diff --git a/lamagraph-compiler/test/golden/eval/source/Forest.lml b/lamagraph-compiler/test/golden/eval/source/Forest.lml new file mode 100644 index 00000000..49b31fef --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/source/Forest.lml @@ -0,0 +1,13 @@ +module Forest + +type 'a tree = Leaf of 'a | Node of 'a forest +and 'a forest = Nil | Cons of 'a tree * 'a forest + +let rec tree_sum t = match t with + | Leaf v -> v + | Node f -> forest_sum f +and forest_sum f = match f with + | Nil -> 0 + | Cons (t, rest) -> (tree_sum t) + (forest_sum rest) + +let _ = print_int (forest_sum (Cons ((Leaf 10), (Cons ((Node (Cons ((Leaf 20), Nil))), Nil))))) diff --git a/lamagraph-compiler/test/golden/eval/source/Insanity.lml b/lamagraph-compiler/test/golden/eval/source/Insanity.lml new file mode 100644 index 00000000..44e5b250 --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/source/Insanity.lml @@ -0,0 +1,54 @@ +module Insanity + +type 'a first = F of 'a * 'a second +and 'a second = S of 'a * 'a third +and 'a third = T of 'a * 'a first | Tempty + +let rec first_sum a = match a with + | F (x, b) -> x + (second_sum b) +and second_sum b = match b with + | S (x, c) -> x + (third_sum c) +and third_sum c = match c with + | Tempty -> 0 + | T (x, a) -> x + (first_sum a) + +let result = print_int (first_sum (F (1, (S (2, (T (3, (F (4, (S (5, Tempty))))))))))) + +let classify_num n = match n with + | 0 -> 100 + | 1 -> 101 + | 2 -> 102 + | 5 -> 105 + | _ -> 999 + +let negate b = match b with + | true -> false + | false -> true + +let to_int b = match b with + | true -> 1 + | false -> 0 + +let bool_and a b = match a with + | true -> (match b with + | true -> true + | false -> false) + | false -> false + +let sign n = match n with + | 0 -> 0 + | n -> match n > 0 with + | true -> 1 + | false -> -1 + +let _ = print_int (classify_num 0) +let _ = print_int (classify_num 1) +let _ = print_int (classify_num 5) +let _ = print_int (classify_num 42) +let _ = print_int (to_int (negate true)) +let _ = print_int (to_int (negate false)) +let _ = print_int (to_int (bool_and true true)) +let _ = print_int (to_int (bool_and true false)) +let _ = print_int (sign 0) +let _ = print_int (sign 42) +let _ = print_int (sign (-10)) diff --git a/lamagraph-compiler/test/golden/eval/source/Option.lml b/lamagraph-compiler/test/golden/eval/source/Option.lml new file mode 100644 index 00000000..f7fe424e --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/source/Option.lml @@ -0,0 +1,49 @@ +module Option + +type 'a option = + | None + | Some of 'a + +let map f opt = + match opt with + | Some x -> Some (f x) + | None -> None + +let mapOrDefault f default opt = + match opt with + | Some x -> f x + | None -> default + +let increment x = x + 1 +let double x = x * 2 + +let f opt = map double (map increment opt) + +type 'a list_of_options = 'a option list + +type 'a option_of_list = 'a list option + +let rec count_somes l = match l with + | [] -> 0 + | hd :: tl -> + let count_tl = count_somes tl in + match hd with + | None -> count_tl + | Some _ -> 1 + count_tl + +let rec sum_list_of_options l = match l with + | [] -> 0 + | hd :: tl -> + let sum_tl = sum_list_of_options tl in + match hd with + | None -> sum_tl + | Some v -> v + sum_tl + +let l_of_opts = (Some 1) :: (None :: ((Some 3) :: ((Some 5) :: []))) + +let _ = print_int (mapOrDefault increment 0 (f (Some 5))) +let _ = print_int (mapOrDefault double 0 (Some 42)) +let _ = print_int (mapOrDefault double 0 None) + +let result1 = print_int (count_somes l_of_opts) +let result2 = print_int (sum_list_of_options l_of_opts) diff --git a/lamagraph-compiler/test/golden/eval/source/Range.lml b/lamagraph-compiler/test/golden/eval/source/Range.lml new file mode 100644 index 00000000..b992382a --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/source/Range.lml @@ -0,0 +1,44 @@ +module Range + +let rec range n = + if n < 1 then [] + else + let tl = range (n - 1) in + n :: tl + +let rec sum_list l = match l with + | [] -> 0 + | hd :: tl -> hd + (sum_list tl) + +let rec length l = match l with + | [] -> 0 + | _ :: tl -> 1 + (length tl) + +let rec map f l = match l with + | hd :: tl -> (f hd) :: (map f tl) + | [] -> [] + +let increment x = x + 1 + +let head_of_head ll = match ll with + | [] -> 0 + | l :: _ -> + match l with + | [] -> 1 + | hd :: _ -> hd + +let r = range 100 + +let l = 1 :: (2 :: (3 :: [])) +let l' = let list_increment = map increment in list_increment l + +let ll = (42 :: 43 :: []) :: (44 :: []) :: [] +let empty_ll = [] :: [] + +let _ = print_int (sum_list r) +let _ = print_int (length r) +let _ = print_int (length l) +let _ = print_int (sum_list l') + +let _ = print_int (head_of_head ll) +let _ = print_int (head_of_head empty_ll) diff --git a/lamagraph-compiler/test/golden/eval/source/Tree.lml b/lamagraph-compiler/test/golden/eval/source/Tree.lml new file mode 100644 index 00000000..638b5341 --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/source/Tree.lml @@ -0,0 +1,10 @@ +module Tree + +type 'a tree = Leaf of 'a | Node of 'a * 'a tree * 'a tree + +let rec sum_tree t = match t with + | Leaf v -> v + | Node (v, left, right) -> v + (sum_tree left) + (sum_tree right) + +let _ = print_int (sum_tree (Node (10, (Node (5, (Leaf 0), (Leaf 0))), (Node (15, (Leaf 0), (Leaf 0)))))) +let _ = print_int (sum_tree (Node (4, (Node (2, (Leaf 1), (Leaf 3))), (Node (6, (Leaf 5), (Leaf 7)))))) diff --git a/lamagraph-compiler/test/golden/eval/source/Tuples.lml b/lamagraph-compiler/test/golden/eval/source/Tuples.lml new file mode 100644 index 00000000..be034b47 --- /dev/null +++ b/lamagraph-compiler/test/golden/eval/source/Tuples.lml @@ -0,0 +1,31 @@ +module Tuples + +type ('a, 'b) pair = Pair of 'a * 'b +type ('a, 'b, 'c) triple = Triple of 'a * 'b * 'c + +let fst p = match p with + | Pair (x, _) -> x + +let snd p = match p with + | Pair (_, y) -> y + +let first_of_int_triple t = match t with + | Triple (x, _, _) -> x + +let second_of_int_triple t = match t with + | Triple (_, y, _) -> y + +let sum_of_first_and_third_of_int_triple t = match t with + | Triple (x, _, z) -> x + z + +let swap p = match p with + | Pair (x, y) -> Pair (y, x) + +let t = Triple (1, 2, 3) + +let _ = print_int (fst (swap (Pair (1, 2)))) +let _ = print_int (fst (Pair (42, true))) +let _ = print_int (snd (Pair (false, 100))) + +let _ = print_int (sum_of_first_and_third_of_int_triple t) +let _ = print_int (second_of_int_triple t)