@@ -43,7 +43,7 @@ import CodeGen.IL.Printer
44import Tests
44import Tests
46−data Command = Build | Run
46+data Command = Build | Run (Maybe String)
48parseJson :: Text -> Value
48parseJson :: Text -> Value
49parseJson text
49parseJson text
@@ -54,12 +54,32 @@ jsonToModule :: Value -> Module Ann
54jsonToModule value =
54jsonToModule value =
55 case parse moduleFromJSON value of
55 case parse moduleFromJSON value of
56 Success (_, r) -> r
56 Success (_, r) -> r
57− _ -> error "failed"
57+ _ -> error "Failed parsing corefn. Psgo currently supports purescript <= 0.13.8"
59+splitArgs :: [String] -> ([String], Maybe String, [String])
61+ let (opts, files) = partition (isPrefixOf "--") args
62+ opts' = (map . map) toLower opts
63+ (moduleName, files') =
65+ then (Nothing, files)
67+ if "--run" `elem` opts' && length (files) >= 1
69+ let file0 = head files
72+ "Main.main" -> (Just "Main", files')
73+ "Test.Main.main" -> (Just "Test.Main", files')
74+ _ -> (Nothing, files)
75+ else (Nothing, files)
76+ in (opts, moduleName, files')
59main :: IO ()
78main :: IO ()
61 args <- getArgs
80 args <- getArgs
62− let (opts, files) = partition (isPrefixOf "--") args
81+ -- let (opts, files) = partition (isPrefixOf "--") args
82+ let (opts, moduleName, files) = splitArgs args
63 opts' = (map . map) toLower opts
83 opts' = (map . map) toLower opts
64 if "--tests" `elem` opts'
84 if "--tests" `elem` opts'
65 then runTests
85 then runTests
@@ -81,7 +101,7 @@ main = do
82 processFiles opts' files
102 processFiles opts' files
83 if "--run" `elem` opts
103 if "--run" `elem` opts
84− then runBuildTool Run
104+ then runBuildTool $ Run moduleName
85 else when ("--no-build" `notElem` opts) $
105 else when ("--no-build" `notElem` opts) $
86 runBuildTool Build
106 runBuildTool Build
87 return ()
107 return ()
@@ -109,11 +129,12 @@ main = do
109 return ()
129 return ()
110 runBuildTool :: Command -> IO ()
130 runBuildTool :: Command -> IO ()
111 runBuildTool cmd = do
131 runBuildTool cmd = do
132+ project <- projectEnv
112− let command = case cmd of
133+ case cmd of
113− Build -> "build"
134+ Build -> do
114− Run -> "run"
135+ callProcess "go" ["build", T.unpack project </> modPrefix' </> "Main"]
115− (_, _, _, p) <- createProcess (proc "go" [command, T.unpack modPrefix <> "/Main"])
136+ Run moduleName -> do
116− waitForProcess p
137+ callProcess "go" ["run", T.unpack project </> modPrefix' </> fromMaybe "Main" moduleName]
117 return ()
138 return ()
119generateCode :: [String] -> FilePath -> FilePath -> IO ()
140generateCode :: [String] -> FilePath -> FilePath -> IO ()
@@ -136,8 +157,9 @@ generateCode opts baseOutpath jsonFile = do
136transpile :: [String] -> FilePath -> FilePath -> IO ()
157transpile :: [String] -> FilePath -> FilePath -> IO ()
137transpile opts baseOutpath jsonFile = do
158transpile opts baseOutpath jsonFile = do
138 jsonText <- T.decodeUtf8 <$> B.readFile jsonFile
159 jsonText <- T.decodeUtf8 <$> B.readFile jsonFile
160+ project <- projectEnv
139 let module' = jsonToModule $ parseJson jsonText
161 let module' = jsonToModule $ parseJson jsonText
140− ((_, foreigns, asts, implHeader, implFooter), _) <- runSupplyT 5 (moduleToIL module' Nothing)
162+ ((_, foreigns, asts, implHeader, implFooter), _) <- runSupplyT 5 (moduleToIL module' project)
141 let mn = moduleNameToIL' $ moduleName module'
163 let mn = moduleNameToIL' $ moduleName module'
142 implementation = prettyPrintIL asts
164 implementation = prettyPrintIL asts
143 outpath = joinPath [baseOutpath, T.unpack mn]
165 outpath = joinPath [baseOutpath, T.unpack mn]
@@ -149,36 +171,50 @@ transpile opts baseOutpath jsonFile = do
149writeSupportFiles :: FilePath -> IO ()
171writeSupportFiles :: FilePath -> IO ()
150writeSupportFiles baseOutpath = do
172writeSupportFiles baseOutpath = do
151 currentDir <- getCurrentDirectory
173 currentDir <- getCurrentDirectory
152− let goModSource = currentDir </> "go.mod"
174+ let outputdir = T.pack $ baseOutpath \\ currentDir
153− goModSourceExists <- doesFileExist goModSource
175+ ffiOutpath = currentDir </> subdir
154− when (not goModSourceExists) $ do
155− let modText = $(embedFile "support/go.mod.working")
156− subdir = baseOutpath \\ currentDir
157− modText' = T.replace "/$OUTPUT" (T.pack subdir) $ T.decodeUtf8 modText
158− B.writeFile goModSource $ T.encodeUtf8 modText'
159 createDirectoryIfMissing True baseOutpath
176 createDirectoryIfMissing True baseOutpath
160− let goModSource = baseOutpath </> "go.mod"
177+ createDirectoryIfMissing True ffiOutpath
161− goModSourceExists <- doesFileExist goModSource
178+ writeModuleFile outputdir currentDir $(embedFile "support/go.mod.working")
162− when (not goModSourceExists) $ do
163− B.writeFile goModSource $(embedFile "support/go.mod.output")
179+ writeModuleFile outputdir baseOutpath $(embedFile "support/go.mod.output")
164− createDirectoryIfMissing True $ currentDir </> "purescript-native"
180+ writeModuleFile outputdir ffiOutpath $(embedFile "support/go.mod.ffi-loader")
181+ writeLoaderFile ffiOutpath $(embedFile "support/ffi-loader.go")
183+ writeModuleFile :: Text -> FilePath -> B.ByteString -> IO ()
184+ writeModuleFile outputdir path modText = do
165− let goModSource = currentDir </> "purescript-native" </> "go.mod"
185+ let goModSource = path </> "go.mod"
166− goModSourceExists <- doesFileExist goModSource
186+ goModSourceExists <- doesFileExist goModSource
167− when (not goModSourceExists) $ do
187+ when (not goModSourceExists) $ do
188+ project <- projectEnv
189+ let project' = T.unpack project
190+ outputdir' = tail $ T.unpack outputdir
191+ modText' = T.replace "$PROJECT" project $ T.decodeUtf8 modText
192+ replaceLoader = project' </> ffiLoader' <> "=." </> subdir
193+ replaceOutput = project' </> modPrefix' <> "=." </> outputdir'
168− B.writeFile goModSource $(embedFile "support/go.mod.ffi-loader")
194+ B.writeFile goModSource $ T.encodeUtf8 modText'
169− let loaderSource = currentDir </> "purescript-native" </> "ffi_loader.go"
195+ callProcess "go" ["mod", "edit", "-replace", replaceLoader]
196+ callProcess "go" ["mod", "edit", "-replace", replaceOutput]
197+ callProcess "go" ["clean", "-modcache"]
198+ writeLoaderFile :: FilePath -> B.ByteString -> IO ()
199+ writeLoaderFile ffiOutpath loaderText = do
200+ let loaderSource = ffiOutpath </> "ffi_loader.go"
170− loaderSourceExists <- doesFileExist loaderSource
201+ loaderSourceExists <- doesFileExist loaderSource
171− when (not loaderSourceExists) $ do
202+ when (not loaderSourceExists) $ do
172− B.writeFile loaderSource $(embedFile "support/ffi-loader.go")
203+ B.writeFile loaderSource loaderText
174implFileName :: Text -> FilePath
205implFileName :: Text -> FilePath
175implFileName mn = ((\c -> if c == '.' then '_' else c) <$> T.unpack mn) <> ".go"
206implFileName mn = ((\c -> if c == '.' then '_' else c) <$> T.unpack mn) <> ".go"
208+projectEnv :: IO Text
210+ T.pack . fromMaybe defaultProject <$> lookupEnv goproject
177help :: String
212help :: String
178help = "Usage: psgo OPTIONS COREFN-FILES\n\
213help = "Usage: psgo OPTIONS COREFN-FILES\n\
179 \ PureScript to native (via go) compiler\n\n\
214 \ PureScript to native (via go) compiler\n\n\
180 \Available options:\n\
215 \Available options:\n\
181 \ --help Show this help text\n\n\
216 \ --help Show this help text\n\n\
217+ \ --version Show the version number\n\n\
182 \ --run Run the generated go code directly, without building an\n\
218 \ --run Run the generated go code directly, without building an\n\
183 \ executable\n\
219 \ executable\n\
184 \ --no-build Generate go source files, but do not build an executable\n\
220 \ --no-build Generate go source files, but do not build an executable\n\
@@ -192,6 +228,21 @@ corefn = "corefn.json"
192goSrc :: String
228goSrc :: String
193goSrc = ".go"
229goSrc = ".go"
232+goproject = "GOPROJECT"
234+defaultProject :: String
235+defaultProject = "project.localhost"
238+modPrefix' = T.unpack modPrefix
241+ffiLoader' = T.unpack ffiLoader
244+subdir = T.unpack modLabel
195errorNoCorefnFiles :: IO ()
246errorNoCorefnFiles :: IO ()
196errorNoCorefnFiles = do
247errorNoCorefnFiles = do
197 ioError . userError $ "no compiled purescript '" <> corefn <> "' files found –\n" <>
248 ioError . userError $ "no compiled purescript '" <> corefn <> "' files found –\n" <>