{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
module Dovetail.Build where
import Control.Monad (foldM)
import Control.Monad.Supply (evalSupplyT)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.State (runStateT)
import Control.Monad.Trans.Writer (runWriterT)
import Data.Foldable (foldl')
import Data.List.NonEmpty (NonEmpty)
import Data.List.NonEmpty qualified as NEL
import Data.Text (Text)
import Language.PureScript qualified as P
import Language.PureScript.AST.Declarations qualified as AST
import Language.PureScript.AST.SourcePos qualified as AST
import Language.PureScript.CoreFn qualified as CoreFn
import Language.PureScript.CST qualified as CST
import Language.PureScript.Errors qualified as Errors
import Language.PureScript.Renamer qualified as Renamer
import Language.PureScript.Sugar.Names.Env qualified as Env
import Language.PureScript.TypeChecker.Monad qualified as TC
data BuildError
= UnableToParse (NonEmpty CST.ParserError)
| UnableToCompile Errors.MultipleErrors
| InternalError
deriving Int -> BuildError -> ShowS
[BuildError] -> ShowS
BuildError -> String
(Int -> BuildError -> ShowS)
-> (BuildError -> String)
-> ([BuildError] -> ShowS)
-> Show BuildError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [BuildError] -> ShowS
$cshowList :: [BuildError] -> ShowS
show :: BuildError -> String
$cshow :: BuildError -> String
showsPrec :: Int -> BuildError -> ShowS
$cshowsPrec :: Int -> BuildError -> ShowS
Show
renderBuildError :: BuildError -> String
renderBuildError :: BuildError -> String
renderBuildError (UnableToParse NonEmpty ParserError
xs) =
[String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
String
"Parser errors:" String -> [String] -> [String]
forall a. a -> [a] -> [a]
: NonEmpty String -> [String]
forall a. NonEmpty a -> [a]
NEL.toList ((ParserError -> String) -> NonEmpty ParserError -> NonEmpty String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ParserError -> String
CST.prettyPrintError NonEmpty ParserError
xs)
renderBuildError (UnableToCompile MultipleErrors
xs) =
PPEOptions -> MultipleErrors -> String
Errors.prettyPrintMultipleErrors PPEOptions
Errors.defaultPPEOptions MultipleErrors
xs
renderBuildError BuildError
InternalError =
String
"An internal error occurred during compilation."
buildSingleModule :: [P.ExternsFile] -> Text -> Either BuildError (CoreFn.Module CoreFn.Ann, P.ExternsFile)
buildSingleModule :: [ExternsFile]
-> Text -> Either BuildError (Module Ann, ExternsFile)
buildSingleModule [ExternsFile]
externs Text
moduleText = do
case String
-> Text -> ([ParserWarning], Either (NonEmpty ParserError) Module)
CST.parseFromFile String
"<input>" Text
moduleText of
([ParserWarning]
_, Left NonEmpty ParserError
errs) ->
BuildError -> Either BuildError (Module Ann, ExternsFile)
forall a b. a -> Either a b
Left (NonEmpty ParserError -> BuildError
UnableToParse NonEmpty ParserError
errs)
([ParserWarning]
_, Right Module
m) ->
case [ExternsFile]
-> Module
-> Either
MultipleErrors ((Module Ann, ExternsFile), MultipleErrors)
buildCoreFnOnly [ExternsFile]
externs Module
m of
Left MultipleErrors
errs ->
BuildError -> Either BuildError (Module Ann, ExternsFile)
forall a b. a -> Either a b
Left (MultipleErrors -> BuildError
UnableToCompile MultipleErrors
errs)
Right ((Module Ann, ExternsFile)
result, MultipleErrors
_) -> (Module Ann, ExternsFile)
-> Either BuildError (Module Ann, ExternsFile)
forall a b. b -> Either a b
Right (Module Ann, ExternsFile)
result
buildSingleExpression
:: Maybe P.ModuleName
-> [P.ExternsFile]
-> Text
-> Either BuildError (CoreFn.Expr CoreFn.Ann, P.SourceType)
buildSingleExpression :: Maybe ModuleName
-> [ExternsFile]
-> Text
-> Either BuildError (Expr Ann, SourceType)
buildSingleExpression = (Expr -> Expr)
-> Maybe ModuleName
-> [ExternsFile]
-> Text
-> Either BuildError (Expr Ann, SourceType)
buildSingleExpressionWith Expr -> Expr
forall a. a -> a
id
buildSingleExpressionWith
:: (AST.Expr -> AST.Expr)
-> Maybe P.ModuleName
-> [P.ExternsFile]
-> Text
-> Either BuildError (CoreFn.Expr CoreFn.Ann, P.SourceType)
buildSingleExpressionWith :: (Expr -> Expr)
-> Maybe ModuleName
-> [ExternsFile]
-> Text
-> Either BuildError (Expr Ann, SourceType)
buildSingleExpressionWith Expr -> Expr
f Maybe ModuleName
defaultModule [ExternsFile]
externs Text
input = do
let tokens :: [LexResult]
tokens = Text -> [LexResult]
CST.lex Text
input
(ParserState
_, Either (NonEmpty ParserError) (Expr ())
parseResult) = ParserState
-> Parser (Expr ())
-> (ParserState, Either (NonEmpty ParserError) (Expr ()))
forall a.
ParserState
-> Parser a -> (ParserState, Either (NonEmpty ParserError) a)
CST.runParser ([LexResult] -> [ParserError] -> [ParserWarning] -> ParserState
CST.ParserState [LexResult]
tokens [] []) Parser (Expr ())
CST.parseExpr
case Either (NonEmpty ParserError) (Expr ())
parseResult of
Left NonEmpty ParserError
errs ->
BuildError -> Either BuildError (Expr Ann, SourceType)
forall a b. a -> Either a b
Left (NonEmpty ParserError -> BuildError
UnableToParse NonEmpty ParserError
errs)
Right Expr ()
cst ->
Maybe ModuleName
-> [ExternsFile]
-> Expr
-> Either BuildError (Expr Ann, SourceType)
buildSingleExpressionFromAST Maybe ModuleName
defaultModule [ExternsFile]
externs (Expr -> Expr
f (String -> Expr () -> Expr
forall a. String -> Expr a -> Expr
CST.convertExpr String
"<input>" Expr ()
cst))
buildSingleExpressionFromAST
:: Maybe P.ModuleName
-> [P.ExternsFile]
-> AST.Expr
-> Either BuildError (CoreFn.Expr CoreFn.Ann, P.SourceType)
buildSingleExpressionFromAST :: Maybe ModuleName
-> [ExternsFile]
-> Expr
-> Either BuildError (Expr Ann, SourceType)
buildSingleExpressionFromAST Maybe ModuleName
defaultModule [ExternsFile]
externs Expr
expr = do
let exprName :: Ident
exprName = Text -> Ident
P.Ident Text
"$"
decl :: ValueDeclarationData [GuardedExpr]
decl = ValueDeclarationData :: forall a.
SourceAnn
-> Ident -> NameKind -> [Binder] -> a -> ValueDeclarationData a
AST.ValueDeclarationData
{ valdeclSourceAnn :: SourceAnn
AST.valdeclSourceAnn = SourceAnn
AST.nullSourceAnn
, valdeclIdent :: Ident
AST.valdeclIdent = Ident
exprName
, valdeclName :: NameKind
AST.valdeclName = NameKind
P.Public
, valdeclBinders :: [Binder]
AST.valdeclBinders = []
, valdeclExpression :: [GuardedExpr]
AST.valdeclExpression = [[Guard] -> Expr -> GuardedExpr
AST.GuardedExpr [] Expr
expr]
}
imports :: [Declaration]
imports = [ SourceAnn
-> ModuleName
-> ImportDeclarationType
-> Maybe ModuleName
-> Declaration
P.ImportDeclaration
SourceAnn
AST.nullSourceAnn
ModuleName
mn
ImportDeclarationType
P.Implicit
(if Maybe ModuleName
defaultModule Maybe ModuleName -> Maybe ModuleName -> Bool
forall a. Eq a => a -> a -> Bool
== ModuleName -> Maybe ModuleName
forall a. a -> Maybe a
Just ModuleName
mn
then Maybe ModuleName
forall a. Maybe a
Nothing
else ModuleName -> Maybe ModuleName
forall a. a -> Maybe a
Just ModuleName
mn)
| P.ExternsFile { efModuleName :: ExternsFile -> ModuleName
P.efModuleName = ModuleName
mn } <- [ExternsFile]
externs
]
m :: Module
m = SourceSpan
-> [Comment]
-> ModuleName
-> [Declaration]
-> Maybe [DeclarationRef]
-> Module
AST.Module SourceSpan
AST.nullSourceSpan [] (Text -> ModuleName
P.ModuleName Text
"$") ([Declaration]
imports [Declaration] -> [Declaration] -> [Declaration]
forall a. Semigroup a => a -> a -> a
<> [ValueDeclarationData [GuardedExpr] -> Declaration
P.ValueDeclaration ValueDeclarationData [GuardedExpr]
decl]) Maybe [DeclarationRef]
forall a. Maybe a
Nothing
case [ExternsFile]
-> Module
-> Either
MultipleErrors ((Module Ann, ExternsFile), MultipleErrors)
buildCoreFnOnly [ExternsFile]
externs Module
m of
Left MultipleErrors
errs ->
BuildError -> Either BuildError (Expr Ann, SourceType)
forall a b. a -> Either a b
Left (MultipleErrors -> BuildError
UnableToCompile MultipleErrors
errs)
Right ((Module Ann
result, ExternsFile
externs'), MultipleErrors
_) ->
case (Module Ann -> [Bind Ann]
forall a. Module a -> [Bind a]
CoreFn.moduleDecls Module Ann
result, ExternsFile -> [ExternsDeclaration]
P.efDeclarations ExternsFile
externs') of
([CoreFn.NonRec Ann
_ Ident
name1 Expr Ann
coreFnExpr], [P.EDValue Ident
name2 SourceType
ty])
| Ident
name1 Ident -> Ident -> Bool
forall a. Eq a => a -> a -> Bool
== Ident
exprName
, Ident
name2 Ident -> Ident -> Bool
forall a. Eq a => a -> a -> Bool
== Ident
exprName -> (Expr Ann, SourceType) -> Either BuildError (Expr Ann, SourceType)
forall a b. b -> Either a b
Right (Expr Ann
coreFnExpr, SourceType
ty)
([CoreFn.Rec [((Ann
_, Ident
name1), Expr Ann
coreFnExpr)]], [P.EDValue Ident
name2 SourceType
ty])
| Ident
name1 Ident -> Ident -> Bool
forall a. Eq a => a -> a -> Bool
== Ident
exprName
, Ident
name2 Ident -> Ident -> Bool
forall a. Eq a => a -> a -> Bool
== Ident
exprName -> (Expr Ann, SourceType) -> Either BuildError (Expr Ann, SourceType)
forall a b. b -> Either a b
Right (Expr Ann
coreFnExpr, SourceType
ty)
([Bind Ann], [ExternsDeclaration])
_ -> BuildError -> Either BuildError (Expr Ann, SourceType)
forall a b. a -> Either a b
Left BuildError
InternalError
buildCoreFnOnly
:: [P.ExternsFile]
-> AST.Module
-> Either Errors.MultipleErrors ((CoreFn.Module CoreFn.Ann, P.ExternsFile), Errors.MultipleErrors)
buildCoreFnOnly :: [ExternsFile]
-> Module
-> Either
MultipleErrors ((Module Ann, ExternsFile), MultipleErrors)
buildCoreFnOnly [ExternsFile]
externs m :: Module
m@(AST.Module SourceSpan
_ [Comment]
_ ModuleName
moduleName [Declaration]
_ Maybe [DeclarationRef]
_) = WriterT
MultipleErrors (Either MultipleErrors) (Module Ann, ExternsFile)
-> Either
MultipleErrors ((Module Ann, ExternsFile), MultipleErrors)
forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT (WriterT
MultipleErrors (Either MultipleErrors) (Module Ann, ExternsFile)
-> Either
MultipleErrors ((Module Ann, ExternsFile), MultipleErrors))
-> WriterT
MultipleErrors (Either MultipleErrors) (Module Ann, ExternsFile)
-> Either
MultipleErrors ((Module Ann, ExternsFile), MultipleErrors)
forall a b. (a -> b) -> a -> b
$ do
let withPrim :: Module
withPrim = Module -> Module
P.importPrim Module
m
env :: Environment
env = (Environment -> ExternsFile -> Environment)
-> Environment -> [ExternsFile] -> Environment
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' ((ExternsFile -> Environment -> Environment)
-> Environment -> ExternsFile -> Environment
forall a b c. (a -> b -> c) -> b -> a -> c
flip ExternsFile -> Environment -> Environment
P.applyExternsFileToEnvironment) Environment
P.initEnvironment [ExternsFile]
externs
Env
exEnv <- ((Env, MultipleErrors) -> Env)
-> WriterT
MultipleErrors (Either MultipleErrors) (Env, MultipleErrors)
-> WriterT MultipleErrors (Either MultipleErrors) Env
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Env, MultipleErrors) -> Env
forall a b. (a, b) -> a
fst (WriterT
MultipleErrors (Either MultipleErrors) (Env, MultipleErrors)
-> WriterT MultipleErrors (Either MultipleErrors) Env)
-> (WriterT
MultipleErrors (WriterT MultipleErrors (Either MultipleErrors)) Env
-> WriterT
MultipleErrors (Either MultipleErrors) (Env, MultipleErrors))
-> WriterT
MultipleErrors (WriterT MultipleErrors (Either MultipleErrors)) Env
-> WriterT MultipleErrors (Either MultipleErrors) Env
forall b c a. (b -> c) -> (a -> b) -> a -> c
. WriterT
MultipleErrors (WriterT MultipleErrors (Either MultipleErrors)) Env
-> WriterT
MultipleErrors (Either MultipleErrors) (Env, MultipleErrors)
forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT (WriterT
MultipleErrors (WriterT MultipleErrors (Either MultipleErrors)) Env
-> WriterT MultipleErrors (Either MultipleErrors) Env)
-> WriterT
MultipleErrors (WriterT MultipleErrors (Either MultipleErrors)) Env
-> WriterT MultipleErrors (Either MultipleErrors) Env
forall a b. (a -> b) -> a -> b
$ (Env
-> ExternsFile
-> WriterT
MultipleErrors
(WriterT MultipleErrors (Either MultipleErrors))
Env)
-> Env
-> [ExternsFile]
-> WriterT
MultipleErrors (WriterT MultipleErrors (Either MultipleErrors)) Env
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM Env
-> ExternsFile
-> WriterT
MultipleErrors (WriterT MultipleErrors (Either MultipleErrors)) Env
forall (m :: * -> *).
(MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
Env -> ExternsFile -> m Env
P.externsEnv Env
Env.primEnv [ExternsFile]
externs
Integer
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors))
(Module Ann, ExternsFile)
-> WriterT
MultipleErrors (Either MultipleErrors) (Module Ann, ExternsFile)
forall (m :: * -> *) a. Functor m => Integer -> SupplyT m a -> m a
evalSupplyT Integer
0 (SupplyT
(WriterT MultipleErrors (Either MultipleErrors))
(Module Ann, ExternsFile)
-> WriterT
MultipleErrors (Either MultipleErrors) (Module Ann, ExternsFile))
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors))
(Module Ann, ExternsFile)
-> WriterT
MultipleErrors (Either MultipleErrors) (Module Ann, ExternsFile)
forall a b. (a -> b) -> a -> b
$ do
(Module
desugared, (Env
exEnv', UsedImports
_)) <- StateT
(Env, UsedImports)
(SupplyT (WriterT MultipleErrors (Either MultipleErrors)))
Module
-> (Env, UsedImports)
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors))
(Module, (Env, UsedImports))
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT ([ExternsFile]
-> Module
-> StateT
(Env, UsedImports)
(SupplyT (WriterT MultipleErrors (Either MultipleErrors)))
Module
forall (m :: * -> *).
(MonadSupply m, MonadError MultipleErrors m,
MonadWriter MultipleErrors m, MonadState (Env, UsedImports) m) =>
[ExternsFile] -> Module -> m Module
P.desugar [ExternsFile]
externs Module
withPrim) (Env
exEnv, UsedImports
forall a. Monoid a => a
mempty)
let modulesExports :: Map ModuleName Exports
modulesExports = (\(SourceSpan
_, Imports
_, Exports
exports) -> Exports
exports) ((SourceSpan, Imports, Exports) -> Exports)
-> Env -> Map ModuleName Exports
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Env
exEnv'
(Module
checked, TC.CheckState{Int
[(SourceAnn, ModuleName, ImportDeclarationType, Maybe ModuleName,
Map
(ProperName 'TypeName)
([ProperName 'ConstructorName], ExportSource))]
[ErrorMessageHint]
Maybe ModuleName
Set (ModuleName, Qualified (ProperName 'ConstructorName))
Substitution
Environment
checkSubstitution :: CheckState -> Substitution
checkNextType :: CheckState -> Int
checkNextSkolemScope :: CheckState -> Int
checkNextSkolem :: CheckState -> Int
checkHints :: CheckState -> [ErrorMessageHint]
checkEnv :: CheckState -> Environment
checkCurrentModuleImports :: CheckState
-> [(SourceAnn, ModuleName, ImportDeclarationType,
Maybe ModuleName,
Map
(ProperName 'TypeName)
([ProperName 'ConstructorName], ExportSource))]
checkCurrentModule :: CheckState -> Maybe ModuleName
checkConstructorImportsForCoercible :: CheckState
-> Set (ModuleName, Qualified (ProperName 'ConstructorName))
checkConstructorImportsForCoercible :: Set (ModuleName, Qualified (ProperName 'ConstructorName))
checkHints :: [ErrorMessageHint]
checkSubstitution :: Substitution
checkCurrentModuleImports :: [(SourceAnn, ModuleName, ImportDeclarationType, Maybe ModuleName,
Map
(ProperName 'TypeName)
([ProperName 'ConstructorName], ExportSource))]
checkCurrentModule :: Maybe ModuleName
checkNextSkolemScope :: Int
checkNextSkolem :: Int
checkNextType :: Int
checkEnv :: Environment
..}) <- StateT
CheckState
(SupplyT (WriterT MultipleErrors (Either MultipleErrors)))
Module
-> CheckState
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors))
(Module, CheckState)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT (Map ModuleName Exports
-> Module
-> StateT
CheckState
(SupplyT (WriterT MultipleErrors (Either MultipleErrors)))
Module
forall (m :: * -> *).
(MonadSupply m, MonadState CheckState m,
MonadError MultipleErrors m, MonadWriter MultipleErrors m) =>
Map ModuleName Exports -> Module -> m Module
P.typeCheckModule Map ModuleName Exports
modulesExports Module
desugared) (CheckState
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors))
(Module, CheckState))
-> CheckState
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors))
(Module, CheckState)
forall a b. (a -> b) -> a -> b
$ Environment -> CheckState
TC.emptyCheckState Environment
env
let AST.Module SourceSpan
ss [Comment]
coms ModuleName
_ [Declaration]
elaborated Maybe [DeclarationRef]
exps = Module
checked
[Declaration]
deguarded <- [Declaration]
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors)) [Declaration]
forall (m :: * -> *).
(MonadSupply m, MonadError MultipleErrors m) =>
[Declaration] -> m [Declaration]
P.desugarCaseGuards [Declaration]
elaborated
[Declaration]
regrouped <- WriterT MultipleErrors (Either MultipleErrors) [Declaration]
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors)) [Declaration]
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (WriterT MultipleErrors (Either MultipleErrors) [Declaration]
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors)) [Declaration])
-> ([Declaration]
-> WriterT MultipleErrors (Either MultipleErrors) [Declaration])
-> [Declaration]
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors)) [Declaration]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ModuleName
-> [Declaration]
-> WriterT MultipleErrors (Either MultipleErrors) [Declaration]
forall (m :: * -> *).
MonadError MultipleErrors m =>
ModuleName -> [Declaration] -> m [Declaration]
P.createBindingGroups ModuleName
moduleName ([Declaration]
-> WriterT MultipleErrors (Either MultipleErrors) [Declaration])
-> ([Declaration] -> [Declaration])
-> [Declaration]
-> WriterT MultipleErrors (Either MultipleErrors) [Declaration]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Declaration] -> [Declaration]
P.collapseBindingGroups ([Declaration]
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors)) [Declaration])
-> [Declaration]
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors)) [Declaration]
forall a b. (a -> b) -> a -> b
$ [Declaration]
deguarded
let mod' :: Module
mod' = SourceSpan
-> [Comment]
-> ModuleName
-> [Declaration]
-> Maybe [DeclarationRef]
-> Module
AST.Module SourceSpan
ss [Comment]
coms ModuleName
moduleName [Declaration]
regrouped Maybe [DeclarationRef]
exps
corefn :: Module Ann
corefn = Environment -> Module -> Module Ann
CoreFn.moduleToCoreFn Environment
checkEnv Module
mod'
optimized :: Module Ann
optimized = Module Ann -> Module Ann
CoreFn.optimizeCoreFn Module Ann
corefn
(Map Ident Ident
renamedIdents, Module Ann
renamed) = Module Ann -> (Map Ident Ident, Module Ann)
Renamer.renameInModule Module Ann
optimized
newExterns :: ExternsFile
newExterns = Module -> Environment -> Map Ident Ident -> ExternsFile
P.moduleToExternsFile Module
mod' Environment
checkEnv Map Ident Ident
renamedIdents
(Module Ann, ExternsFile)
-> SupplyT
(WriterT MultipleErrors (Either MultipleErrors))
(Module Ann, ExternsFile)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Module Ann
renamed, ExternsFile
newExterns)