content: module Compile
    ( Artifacts (..),
      compile,
    )
  where
  
  import AST.Canonical qualified as Can
  import AST.Optimized qualified as Opt
  import AST.Source qualified as Src
  import Canonicalize.Module qualified as Canonicalize
  import Data.Map qualified as Map
  import Data.Name qualified as Name
  import Gren.Interface qualified as I
  import Gren.ModuleName qualified as ModuleName
  import Gren.Package qualified as Pkg
  import Gren.Platform qualified as P
  import Nitpick.PatternMatches qualified as PatternMatches
  import Optimize.Module qualified as Optimize
  import Reporting.Error qualified as E
  import Reporting.Render.Type.Localizer qualified as Localizer
  import Reporting.Result qualified as R
  import System.IO.Unsafe (unsafePerformIO)
  import Type.Constrain.Module qualified as Type
  import Type.Solve qualified as Type
  
  -- COMPILE
  
  data Artifacts = Artifacts
    { _modul :: Can.Module,
      _types :: Map.Map Name.Name Can.Annotation,
      _graph :: Opt.LocalGraph
    }
  
  compile :: P.Platform -> Pkg.Name -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> Either E.Error Artifacts
  compile platform pkg ifaces modul =
    do
      canonical <- canonicalize pkg ifaces modul
      annotations <- typeCheck modul canonical
      () <- nitpick canonical
      objects <- optimize platform modul annotations canonical
      return (Artifacts canonical annotations objects)
  
  -- PHASES
  
  canonicalize :: Pkg.Name -> Map.Map ModuleName.Raw I.Interface -> Src.Module -> Either E.Error Can.Module
  canonicalize pkg ifaces modul =
    case snd $ R.run $ Canonicalize.canonicalize pkg ifaces modul of
      Right canonical ->
        Right canonical
      Left errors ->
        Left $ E.BadNames errors
  
  typeCheck :: Src.Module -> Can.Module -> Either E.Error (Map.Map Name.Name Can.Annotation)
  typeCheck modul canonical =
    case unsafePerformIO (Type.run =<< Type.constrain canonical) of
      Right annotations ->
        Right annotations
      Left errors ->
        Left (E.BadTypes (Localizer.fromModule modul) errors)
  
  nitpick :: Can.Module -> Either E.Error ()
  nitpick canonical =
    case PatternMatches.check canonical of
      Right () ->
        Right ()
      Left errors ->
        Left (E.BadPatterns errors)
  
  optimize :: P.Platform -> Src.Module -> Map.Map Name.Name Can.Annotation -> Can.Module -> Either E.Error Opt.LocalGraph
  optimize platform modul annotations canonical =
    case snd $ R.run $ Optimize.optimize platform annotations canonical of
      Right localGraph ->
        Right localGraph
      Left errors ->
        Left (E.BadMains (Localizer.fromModule modul) errors)
  