git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Golang modules support
commit4e021f17e3d44f1c4aae753807443f134332d2b2 authorAndy Arvanitis <andyarvanitis@gmail.com> dateTue 6 Aug 2019, 20:11 (7 years ago) parent73a8b52
11 files changed+94−166
app/Main.hs+34−34 src/CodeGen/IL/Common.hs+6−9 src/CodeGen/IL/Optimizer/Common.hs+1−3 src/CodeGen/IL/Optimizer/Inliner.hs+1−1 src/CodeGen/IL/Optimizer/MagicDo.hs+1−1 src/CodeGen/IL/Printer.hs+15−4 support/Makefile−114 support/ffi-loader.go+23 support/go.mod.ffi-loader+2 support/go.mod.output+2 support/go.mod.working+9
app/Main.hs+34−34
@@ -10,7 +10,7 @@ import Data.Aeson
1010import Data.Aeson.Types
1111import Data.Char
1212import Data.FileEmbed (embedFile)
13−import Data.List (delete, intercalate, isPrefixOf, nub, partition)
13+import Data.List (delete, intercalate, isPrefixOf, nub, partition, (\\))
1414import Data.Maybe
1515import Data.Monoid ((<>))
1616import Data.Version
@@ -20,7 +20,7 @@ import Text.Printf
2020
2121import System.Environment
2222import System.Directory (createDirectoryIfMissing, doesDirectoryExist, doesFileExist, getCurrentDirectory, getModificationTime)
23−import System.FilePath ((</>), joinPath, searchPathSeparator, splitDirectories, takeDirectory)
23+import System.FilePath ((</>), joinPath, splitDirectories, takeDirectory)
2424import System.FilePath.Find
2525import System.Process
2626
@@ -100,11 +100,11 @@ main = do
100100 basePath :: [FilePath] -> FilePath
101101 basePath files =
102102 let filepath = takeDirectory (head files) in
103− joinPath $ (init $ splitDirectories filepath) ++ [outdir]
103+ joinPath $ (init $ splitDirectories filepath)
104104 generateFiles :: [String] -> [FilePath] -> IO ()
105105 generateFiles opts files = do
106106 let baseOutpath = basePath files
107− writeRuntimeFiles baseOutpath
107+ writeSupportFiles baseOutpath
108108 Par.mapM (generateCode opts baseOutpath) files
109109 return ()
110110 runBuildTool :: Command -> IO ()
@@ -112,33 +112,19 @@ main = do
112112 let command = case cmd of
113113 Build -> "build"
114114 Run -> "run"
115− currentDir <- getCurrentDirectory
116− files <- find always (extension ==? goSrc) currentDir
117− let fileDirs = nub $ joinPath . init <$> filter isSrc (getDir <$> files)
118− currentEnv <- getEnvironment
119− let pathDirs = maybe id (:) (lookup "GOPATH" currentEnv) $ fileDirs
120− searchPath = intercalate [searchPathSeparator] pathDirs
121− env = ("GOPATH", searchPath) : currentEnv
122− (_, _, _, p) <- createProcess (proc "go" [command, "Main"]){ env = Just env }
115+ (_, _, _, p) <- createProcess (proc "go" [command, T.unpack modPrefix <> "/Main"])
123116 waitForProcess p
124117 return ()
125− where
126− getDir :: FilePath -> [FilePath]
127− getDir file =
128− let filepath = takeDirectory file in
129− init $ splitDirectories filepath
130− isSrc :: [FilePath] -> Bool
131− isSrc components = (last components) == "src"
132118
133119generateCode :: [String] -> FilePath -> FilePath -> IO ()
134120generateCode opts baseOutpath jsonFile = do
135121 jsonModTime <- getModificationTime jsonFile
136122 let filepath = takeDirectory jsonFile
137123 dirparts = splitDirectories $ filepath
138− mname = (\c -> if c == '.' then '_' else c) <$> last dirparts
124+ mname = last dirparts
139125 basedir = joinPath $ init dirparts
140− mname' = moduleNameToIL' $ T.pack mname
141− possibleFileName = basedir </> outdir </> (T.unpack mname') </> implFileName mname'
126+ mname' = T.pack mname
127+ possibleFileName = basedir </> (T.unpack mname') </> implFileName mname'
142128 exists <- doesFileExist possibleFileName
143129 if exists
144130 then do
@@ -152,7 +138,7 @@ transpile opts baseOutpath jsonFile = do
152138 jsonText <- T.decodeUtf8 <$> B.readFile jsonFile
153139 let module' = jsonToModule $ parseJson jsonText
154140 ((_, foreigns, asts, implHeader, implFooter), _) <- runSupplyT 5 (moduleToIL module' Nothing)
155− let mn = moduleNameToIL $ moduleName module'
141+ let mn = moduleNameToIL' $ moduleName module'
156142 implementation = prettyPrintIL asts
157143 outpath = joinPath [baseOutpath, T.unpack mn]
158144 implPath = outpath </> implFileName mn
@@ -160,19 +146,33 @@ transpile opts baseOutpath jsonFile = do
160146 putStrLn implPath
161147 B.writeFile implPath $ T.encodeUtf8 (implHeader <> implementation <> implFooter)
162148
163−writeRuntimeFiles :: FilePath -> IO ()
164−writeRuntimeFiles baseOutpath = do
165− createDirectoryIfMissing True $ baseOutpath </> "purescript"
166− let runtimeSource = baseOutpath </> "purescript" </> "purescript.go"
167− runtimeExists <- doesFileExist runtimeSource
168− when (not runtimeExists) $ do
169− B.writeFile runtimeSource $(embedFile "runtime/purescript.go")
170−
171−outdir :: FilePath
172−outdir = "src"
149+writeSupportFiles :: FilePath -> IO ()
150+writeSupportFiles baseOutpath = do
151+ currentDir <- getCurrentDirectory
152+ let goModSource = currentDir </> "go.mod"
153+ goModSourceExists <- doesFileExist goModSource
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
160+ let goModSource = baseOutpath </> "go.mod"
161+ goModSourceExists <- doesFileExist goModSource
162+ when (not goModSourceExists) $ do
163+ B.writeFile goModSource $(embedFile "support/go.mod.output")
164+ createDirectoryIfMissing True $ currentDir </> "purescript-native"
165+ let goModSource = currentDir </> "purescript-native" </> "go.mod"
166+ goModSourceExists <- doesFileExist goModSource
167+ when (not goModSourceExists) $ do
168+ B.writeFile goModSource $(embedFile "support/go.mod.ffi-loader")
169+ let loaderSource = currentDir </> "purescript-native" </> "ffi_loader.go"
170+ loaderSourceExists <- doesFileExist loaderSource
171+ when (not loaderSourceExists) $ do
172+ B.writeFile loaderSource $(embedFile "support/ffi-loader.go")
173173
174174implFileName :: Text -> FilePath
175−implFileName mn = T.unpack $ mn <> ".go"
175+implFileName mn = ((\c -> if c == '.' then '_' else c) <$> T.unpack mn) <> ".go"
176176
177177help :: String
178178help = "Usage: psgo OPTIONS COREFN-FILES\n\
src/CodeGen/IL/Common.hs+6−9
@@ -16,13 +16,10 @@ import Language.PureScript.Names
1616import qualified Language.PureScript.Constants as C
1717
1818moduleNameToIL :: ModuleName -> Text
19−moduleNameToIL (ModuleName pns) =
20− let name = T.intercalate "_" (runProperName `map` pns)
21− in moduleNameToIL' name
19+moduleNameToIL (ModuleName pns) = T.intercalate "_" (runProperName `map` pns)
2220
23−moduleNameToIL' :: Text -> Text
24−moduleNameToIL' name =
25− if moduleIsReserved name then (name <> "_") else name
21+moduleNameToIL' :: ModuleName -> Text
22+moduleNameToIL' (ModuleName pns) = T.intercalate "." (runProperName `map` pns)
2623
2724-- | Convert an 'Ident' into a valid IL identifier:
2825--
@@ -113,9 +110,9 @@ ilKeywords =
113110 , "var"
114111 ]
115112
116−moduleIsReserved :: Text -> Bool
117−moduleIsReserved "Main" = False
118−moduleIsReserved name = not $ T.isInfixOf "_" name
113+-- moduleIsReserved :: Text -> Bool
114+-- moduleIsReserved "Main" = False
115+-- moduleIsReserved name = not $ T.isInfixOf "_" name
119116
120117prefixIsReserved :: Text -> Bool
121118prefixIsReserved name =
src/CodeGen/IL/Optimizer/Common.hs+1−3
@@ -8,11 +8,9 @@ import Data.Text (Text)
88import Language.PureScript.CoreImp.AST
99import Language.PureScript.PSString (PSString, decodeString)
1010
11−import CodeGen.IL.Common (moduleNameToIL')
12−
1311isDict :: (Text, PSString) -> AST -> Bool
1412isDict (moduleName, dictName) (Indexer _ (Var _ x) (Var _ y)) =
15− Just x == decodeString dictName && y == moduleNameToIL' moduleName
13+ Just x == decodeString dictName && y == moduleName
1614isDict _ _ = False
1715
1816isDict' :: [(Text, PSString)] -> AST -> Bool
src/CodeGen/IL/Optimizer/Inliner.hs+1−1
@@ -265,7 +265,7 @@ inlineFnComposition = everywhereTopDownM convert where
265265inlineUnsafeCoerce :: AST -> AST
266266inlineUnsafeCoerce = everywhereTopDown convert where
267267 convert (App _ (Indexer _ (Var _ unsafeCoerceFn) (Var _ unsafeCoerce)) [ comp ])
268− | unsafeCoerceFn == C.unsafeCoerceFn && unsafeCoerce == moduleNameToIL' C.unsafeCoerce
268+ | unsafeCoerceFn == C.unsafeCoerceFn && unsafeCoerce == C.unsafeCoerce
269269 = comp
270270 convert other = other
271271
src/CodeGen/IL/Optimizer/MagicDo.hs+1−1
@@ -13,7 +13,7 @@ import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict)
1313import Language.PureScript.PSString (PSString, decodeString, mkString)
1414import qualified Language.PureScript.Constants as C
1515
16−import CodeGen.IL.Common (moduleNameToIL', undefinedName, unusedName)
16+import CodeGen.IL.Common (undefinedName, unusedName)
1717import CodeGen.IL.Optimizer.Common
1818
1919-- | Inline type class dictionaries for >>= and return for the Eff monad
src/CodeGen/IL/Printer.hs+15−4
@@ -7,6 +7,7 @@ module CodeGen.IL.Printer
77 , implHeaderSource
88 , implFooterSource
99 , isLiteral
10+ , modPrefix
1011 ) where
1112
1213import Prelude.Compat
@@ -439,18 +440,19 @@ interfaceSource _ _ _ = ""
439440
440441implHeaderSource :: Text -> [Text] -> Text -> Text
441442implHeaderSource mn imports _ =
443+ let imports' = T.replace "_" "." <$> imports in
442444 "// Code generated by psgo. DO NOT EDIT.\n\n" <>
443445 "package " <> (if mn == "Main" then "main" else mn) <> "\n\n" <>
444− "import . \"purescript\"\n" <>
446+ "import . \"" <> runtime <> "\"\n" <>
445447 (if mn == "Main"
446− then "import _ \"ffi\"\n"
448+ then "import _ \"" <> ffiLoader <> "\"\n"
447449 else "\n") <>
448450 "import (\n" <>
449− (T.concat $ formatImport <$> imports) <> ")\n\n" <>
451+ (T.concat $ formatImport <$> imports') <> ")\n\n" <>
450452 "type _ = Any\n\n"
451453 where
452454 formatImport :: Text -> Text
453− formatImport s = " \"" <> s <> "\"\n"
455+ formatImport s = " \"" <> modPrefix <> "/" <> s <> "\"\n"
454456
455457implFooterSource :: Text -> [Ident] -> Text
456458implFooterSource mn foreigns =
@@ -494,6 +496,15 @@ foreignMod = "Foreign"
494496foreignDict :: Text
495497foreignDict = "foreign"
496498
499+modPrefix :: Text
500+modPrefix = "purescript-native/output"
501+
502+runtime :: Text
503+runtime = "github.com/purescript-native/go-runtime"
504+
505+ffiLoader :: Text
506+ffiLoader = "purescript-native/ffi-loader"
507+
497508initName :: Text -> Text
498509initName s = "ₒ" <> s
499510
support/Makefiledeleted−114
@@ -1,114 +0,0 @@
1−# PureScript to native binary (via Go) Makefile
2−#
3−# Run 'make' or 'make release' to build an optimized release build
4−# Run 'make debug' to build a non-optimized build suitable for debugging
5−#
6−# You can also perform a parallel build with 'make -jN', where N is the
7−# number of cores to use.
8−#
9−# PURS, SRC, OUTPUT, and BIN can all be overridden with the
10−# command itself. For example: 'make BIN=myutil'
11−#
12−# Flags can be added to either the codegen or native build phases.
13−# For example: 'make PURSFLAGS=--codegen,js CXXFLAGS=-DDEBUG LDFLAGS=lgmp'
14−#
15−# You can also edit the generated version of this file directly.
16−#
17−PURS := purs
18−PSC_PACKAGE := psc-package
19−PSGO := psgo
20−SRC := src
21−OUTPUT := output
22−CC_SRC := $(OUTPUT)/src
23−FFI_SRC := purescript-go-ffi
24−BIN := Main
25−
26−override PURSFLAGS += compile --codegen corefn
27−override CXXFLAGS += --std=c++11
28−
29−DEBUG := "-DDEBUG -g"
30−RELEASE := "-DNDEBUG -O3"
31−
32−GOPATH := $(GOPATH):$(CURDIR)/$(OUTPUT):$(CURDIR)/$(FFI_SRC)
33−
34−INCLUDES := -I $(CC_SRC)
35−BIN_DIR := $(OUTPUT)/bin
36−
37−PACKAGE_SOURCES = $(subst \,/,$(shell $(PSC_PACKAGE) sources))
38−PURESCRIPT_PKGS := $(firstword $(subst /, ,$(PACKAGE_SOURCES)))
39−
40−## Not all environments support globstar (** dir pattern)
41−rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
42−
43−unspecified:
44− @echo
45− @echo "Please specify the type of build you want: 'debug' or 'release'"
46− @echo
47− @echo " debug => not optimized (your app will run slower), good for"
48− @echo " running in a source-level debugger, more (descriptive)"
49− @echo " runtime exceptions"
50− @echo
51− @echo " release => optimized (your app will run faster), less helpful when debugging"
52− @echo
53−
54−debug: codegen
55− go build -o $(BIN_DIR)/$(BIN) $(BIN)
56−
57−release: codegen
58− go build -o $(BIN_DIR)/$(BIN) $(BIN)
59−
60−.PHONY: corefn
61−corefn: PURESCRIPT_PKG_SRCS=$(foreach d,$(PACKAGE_SOURCES),$(call rwildcard,$(firstword $(subst *, ,$(d))),*.purs))
62−corefn: PURESCRIPT_SRCS=$(call rwildcard,$(SRC)/,*.purs)
63−corefn: $(PURESCRIPT_PKGS)
64− @$(PURS) $(PURSFLAGS) --output $(OUTPUT) $(PURESCRIPT_PKG_SRCS) $(PURESCRIPT_SRCS)
65−
66−.PHONY: codegen
67−codegen: COREFN_SRCS=$(call rwildcard,$(OUTPUT)/,corefn.json)
68−codegen: corefn
69− @$(PSGO) $(PSGOFLAGS) $(COREFN_SRCS)
70−
71−$(PURESCRIPT_PKGS):
72− @echo "Getting packages using" $(PSC_PACKAGE) "..."
73− @$(PSC_PACKAGE) update
74−
75−SRCS := $(call rwildcard,$(CC_SRC)/,*.cpp)
76−SRCS += $(call rwildcard,$(FFI_SRC)/,*.cpp)
77−SRCS += $(call rwildcard,$(FFI_SRC)/,*.cc)
78−SRCS += $(call rwildcard,$(FFI_SRC)/,*.c)
79−
80−OBJS1 = $(SRCS:.cpp=.o)
81−OBJS2 = $(OBJS1:.cc=.o)
82−OBJS = $(OBJS2:.c=.o)
83−DEPS = $(OBJS:.o=.d)
84−
85−$(BIN): $(OBJS)
86− @echo "Linking" $(BIN_DIR)/$(BIN)
87− @mkdir -p $(BIN_DIR)
88− @$(CXX) $^ -o $(BIN_DIR)/$@ $(LDFLAGS)
89−
90−-include $(DEPS)
91−
92−%.o: %.cpp
93− @echo "Creating" $@ "(C++)"
94− @$(CXX) $(CXXFLAGS) $(INCLUDES) -MMD -MP -c $< -o $@
95−
96−%.o: %.cc
97− @echo "Creating" $@ "(C++)"
98− @$(CXX) $(CXXFLAGS) $(INCLUDES) -MMD -MP -c $< -o $@
99−
100−%.o: %.c
101− @echo "Creating" $@ "(C)"
102− @$(CXX) $(CFLAGS) $(INCLUDES) -MMD -MP -c $< -o $@
103−
104−.PHONY: all
105−all: release
106−
107−.PHONY: clean
108−clean:
109− @-rm -f $(OBJS) $(DEPS)
110− @-rm -rf $(OUTPUT)
111−
112−.PHONY: run
113−run:
114− @$(BIN_DIR)/$(BIN) $(ARGS)
support/ffi-loader.gonew file+23
@@ -0,0 +1,23 @@
1+package ffi_loader
2+
3+// Load PureScript standard library FFI packages. Comment out the ones you don't need for
4+// faster/smaller builds.
5+
6+import (
7+ _ "github.com/purescript-native/go-ffi/purescript-arrays"
8+ _ "github.com/purescript-native/go-ffi/purescript-assert"
9+ _ "github.com/purescript-native/go-ffi/purescript-console"
10+ _ "github.com/purescript-native/go-ffi/purescript-effect"
11+ _ "github.com/purescript-native/go-ffi/purescript-foldable-traversable"
12+ _ "github.com/purescript-native/go-ffi/purescript-functions"
13+ _ "github.com/purescript-native/go-ffi/purescript-partial"
14+ _ "github.com/purescript-native/go-ffi/purescript-prelude"
15+ _ "github.com/purescript-native/go-ffi/purescript-random"
16+ _ "github.com/purescript-native/go-ffi/purescript-refs"
17+ _ "github.com/purescript-native/go-ffi/purescript-st"
18+ _ "github.com/purescript-native/go-ffi/purescript-strings"
19+)
20+
21+// Add your own FFI packages here.
22+
23+import ()
support/go.mod.ffi-loadernew file+2
@@ -0,0 +1,2 @@
1+module purescript-native/ffi-loader
2+
support/go.mod.outputnew file+2
@@ -0,0 +1,2 @@
1+module purescript-native/output
2+
support/go.mod.workingnew file+9
@@ -0,0 +1,9 @@
1+module example.com/example
2+
3+require purescript-native/output v0.0.0
4+
5+replace purescript-native/output => ./$OUTPUT/
6+
7+require purescript-native/ffi-loader v0.0.0
8+
9+replace purescript-native/ffi-loader => ./purescript-native/