diff --git a/compiler/src/Gren/Format/Normalize.hs b/compiler/src/Gren/Format/Normalize.hs new file mode 100644 index 00000000..3a59814f --- /dev/null +++ b/compiler/src/Gren/Format/Normalize.hs @@ -0,0 +1,65 @@ +{-# LANGUAGE MagicHash #-} + +-- | This module is the "normalization" phase that transforms the raw source AST +-- into an AST ready for rendering back into a text representation. +-- +-- This is simply a place to put "formatting" logic that doesn't really make sense +-- as a responsibility for the code that is rendering the AST into text. +module Gren.Format.Normalize (normalize) where + +import AST.Source qualified as Src +import Data.Map (Map) +import Data.Map qualified as Map +import Data.Maybe (mapMaybe) +import Data.Name (Name) +import Gren.Compiler.Imports qualified +import Reporting.Annotation qualified as A + +normalize :: Src.Module -> Src.Module +normalize module_ = + module_ + { Src._imports = mapMaybe removeDefaultImports $ Src._imports module_ + } + +removeDefaultImports :: Src.Import -> Maybe Src.Import +removeDefaultImports import_@(Src.Import name alias exposing) = + case Map.lookup (A.toValue name) defaultImports of + Just (Src.Import _ defAlias defExposing) -> + if alias == defAlias && exposingEq exposing defExposing + then Nothing + else Just import_ + Nothing -> Just import_ + +defaultImports :: Map Name Src.Import +defaultImports = + Map.fromList $ fmap (\import_ -> (Src.getImportName import_, import_)) Gren.Compiler.Imports.defaults + +exposingEq :: Src.Exposing -> Src.Exposing -> Bool +exposingEq Src.Open Src.Open = True +exposingEq (Src.Explicit a) (Src.Explicit b) = + fmap stripRegionsExposed a == fmap stripRegionsExposed b +exposingEq _ _ = False + +data SimpleExposed + = Lower Name + | Upper Name SimplePrivacy + | Operator Name + deriving (Eq) + +data SimplePrivacy + = Public + | Private + deriving (Eq) + +stripRegionsExposed :: Src.Exposed -> SimpleExposed +stripRegionsExposed exposed = + case exposed of + Src.Lower (A.At _ name) -> Lower name + Src.Upper (A.At _ name) priv -> Upper name (stripRegionsPrivacy priv) + Src.Operator _ name -> Operator name + +stripRegionsPrivacy :: Src.Privacy -> SimplePrivacy +stripRegionsPrivacy priv = + case priv of + Src.Public _ -> Public + Src.Private -> Private diff --git a/gren.cabal b/gren.cabal index b359086a..7b81ad4d 100644 --- a/gren.cabal +++ b/gren.cabal @@ -95,6 +95,7 @@ Common gren-common Gren.Docs Gren.Float Gren.Format + Gren.Format.Normalize Gren.Interface Gren.Kernel Gren.Licenses diff --git a/terminal/src/Format.hs b/terminal/src/Format.hs index 927c58fe..449d86d0 100644 --- a/terminal/src/Format.hs +++ b/terminal/src/Format.hs @@ -15,6 +15,7 @@ import Data.NonEmptyList qualified as NE import Directories qualified as Dirs import File qualified import Gren.Format qualified as Format +import Gren.Format.Normalize qualified as Normalize import Gren.Outline qualified as Outline import Parse.Module qualified as Parse import Reporting qualified @@ -173,4 +174,4 @@ formatByteString original = -- TODO: report error Nothing Right ast -> - Just (Format.toByteStringBuilder ast) + Just (Format.toByteStringBuilder $ Normalize.normalize ast)