<commit_before>module Initialize (build, buildFromSource) where

import Control.Applicative ((<$>))
import Control.Monad.Error
import Data.List (lookup,nub)

import Ast
import Data.Either (lefts,rights)
import Data.List (intercalate,partition)
import Parse.Parser (parseProgram, preParse)
import Rename
import Types.Types ((-:))
import Types.Hints (hints)
import Types.Unify
import Types.Alias
import Optimize
import CompileToJS (jsModule)

checkMistakes :: Module -> Either String Module
checkMistakes modul@(Module name ex im stmts) = 
  case mistakes stmts of
    m:ms -> Left (unlines (m:ms))
    []   -> return modul

checkTypes :: Module -> Either String Module
checkTypes (Module name ex im stmts) =
    let stmts' = dealias stmts
        modul = Module name ex im stmts'
    in do subs <- unify hints modul
          let --im' | any ((=="Prelude") . fst) im = im
              --    | otherwise = ("Prelude", Importing []) : im
              modul' = optimize . renameModule $ Module name ex im stmts'
          subs `seq` return modul'

check :: Module -> Either String Module
check = checkMistakes >=> checkTypes

buildFromSource :: String -> Either String Module
buildFromSource src = check =<< parseProgram src

build :: FilePath -> IO (Either String [Module])
build root = do
  names <- getSortedModuleNames root
  case names of
    Left err -> return (Left err)
    Right ns -> do srcs <- zipWithM buildFile' [1..] ns
                   return (sequence srcs)
      where
        buildFile' n name = putStrLn (msg n name) >> buildFile name
        msg n name = "["++show n++" of "++show (length ns)++"] Compiling "++name

buildFile :: String -> IO (Either String Module)
buildFile moduleName =
  let filePath = toFilePath moduleName in
  case isNative moduleName of
    True  -> return (Right $ Module [moduleName] [] [] [])
             --return (Left "Can't do that yet")
             --Right `liftM` readFile filePath
    False -> do txt <- readFile filePath
                return $ buildFromSource txt


getSortedModuleNames :: FilePath -> IO (Either String [String])
getSortedModuleNames root = do
  deps <- readDeps [] root
  return (sortDeps =<< deps)

type Deps = (String, [String])

sortDeps :: [Deps] -> Either String [String]
sortDeps deps = go [] (nub deps)
    where
      msg = "A cyclical or missing module dependency or was detected in: "

      go :: [String] -> [Deps] -> Either String [String]
      go sorted [] = Right sorted
      go sorted unsorted =
          case partition (all (`elem` sorted) . snd) unsorted of
            ([],m:ms) -> Left (msg ++ intercalate ", " (map fst (m:ms)) ++ show sorted ++ show unsorted)
            (srtd,unsrtd) -> go (sorted ++ map fst srtd) unsrtd

readDeps :: [FilePath] -> FilePath -> IO (Either String [Deps])
readDeps seen root = do
  txt <- readFile root
  case preParse txt of
    Left err -> return (Left err)
    Right (name,deps) -> do rest <- mapM (readDeps seen' . toFilePath) newDeps
                            return $ do rs <- sequence rest
                                        return ((name, realDeps) : concat rs)
        where realDeps = filter (`notElem` builtIns) deps
              newDeps = filter (`notElem` seen) realDeps
              seen' = root : seen ++ newDeps
              builtIns = [] {--
                ["List","Char","Either","Maybe","Dict","Set","Date",
                 "Signal","Mouse","Keyboard.Raw","Keyboard","Touch",
                 "WebSocket","Window","Time","HTTP","Input","Random",
                 "Graphics","Text","Color","JavaScript","Automaton",
                 "JavaScript.Experimental","Prelude","JSON"]
                 --}

isNative name = takeWhile (/='.') name == "Native"
toFilePath name = map swapDots name ++ ext
    where swapDots '.' = '/'
          swapDots  c  =  c
          ext = if isNative name then ".js" else ".elm"<commit_msg>Ensure that --make skips trying to read libraries as files.<commit_after>module Initialize (build, buildFromSource) where

import Control.Applicative ((<$>))
import Control.Monad.Error
import Data.List (lookup,nub)
import qualified Data.Map as Map

import Ast
import Data.Either (lefts,rights)
import Data.List (intercalate,partition)
import Parse.Parser (parseProgram, preParse)
import Rename
import Libraries (libraries)
import Types.Types ((-:))
import Types.Hints (hints)
import Types.Unify
import Types.Alias
import Optimize
import CompileToJS (jsModule)

checkMistakes :: Module -> Either String Module
checkMistakes modul@(Module name ex im stmts) = 
  case mistakes stmts of
    m:ms -> Left (unlines (m:ms))
    []   -> return modul

checkTypes :: Module -> Either String Module
checkTypes (Module name ex im stmts) =
    let stmts' = dealias stmts
        modul = Module name ex im stmts'
    in do subs <- unify hints modul
          let modul' = optimize . renameModule $ Module name ex im stmts'
          subs `seq` return modul'

check :: Module -> Either String Module
check = checkMistakes >=> checkTypes

buildFromSource :: String -> Either String Module
buildFromSource src = check =<< parseProgram src

build :: FilePath -> IO (Either String [Module])
build root = do
  names <- getSortedModuleNames root
  case names of
    Left err -> return (Left err)
    Right ns -> do srcs <- zipWithM buildFile' [1..] ns
                   return (sequence srcs)
      where
        buildFile' n name = putStrLn (msg n name) >> buildFile name
        msg n name = "["++show n++" of "++show (length ns)++"] Compiling "++name

buildFile :: String -> IO (Either String Module)
buildFile moduleName =
  let filePath = toFilePath moduleName in
  case isNative moduleName of
    True  -> return (Right $ Module [moduleName] [] [] [])
             --return (Left "Can't do that yet")
             --Right `liftM` readFile filePath
    False -> do txt <- readFile filePath
                return $ buildFromSource txt


getSortedModuleNames :: FilePath -> IO (Either String [String])
getSortedModuleNames root = do
  deps <- readDeps [] root
  return (sortDeps =<< deps)

type Deps = (String, [String])

sortDeps :: [Deps] -> Either String [String]
sortDeps deps = go [] (nub deps)
    where
      msg = "A cyclical or missing module dependency or was detected in: "

      go :: [String] -> [Deps] -> Either String [String]
      go sorted [] = Right sorted
      go sorted unsorted =
          case partition (all (`elem` sorted) . snd) unsorted of
            ([],m:ms) -> Left (msg ++ intercalate ", " (map fst (m:ms)) ++ show sorted ++ show unsorted)
            (srtd,unsrtd) -> go (sorted ++ map fst srtd) unsrtd

readDeps :: [FilePath] -> FilePath -> IO (Either String [Deps])
readDeps seen root = do
  txt <- readFile root
  case preParse txt of
    Left err -> return (Left err)
    Right (name,deps) -> do rest <- mapM (readDeps seen' . toFilePath) newDeps
                            return $ do rs <- sequence rest
                                        return ((name, realDeps) : concat rs)
        where realDeps = filter (`notElem` builtIns) deps
              newDeps = filter (`notElem` seen) realDeps
              seen' = root : seen ++ newDeps
              builtIns = Map.keys libraries

isNative name = takeWhile (/='.') name == "Native"
toFilePath name = map swapDots name ++ ext
    where swapDots '.' = '/'
          swapDots  c  =  c
          ext = if isNative name then ".js" else ".elm"
{'fraction_non_alphanumeric': 0.11786969451203028, 'fraction_numerical': 0.0002703433360367667, 'mean_word_length': 2.61279296875, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1320346', 'n_tokens_mistral': 2223, 'n_tokens_neox': 2151, 'n_words': 779}