git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Initial impl; only very basic testing done
commit9d25c0e35a7516f66b5413759da193cc6ae67aee authorAndy Arvanitis <andyarvanitis@gmail.com> dateSat 22 Jun 2019, 20:54 (7 years ago) parent127af89
7 files changed+288−329
app/Main.hs+2−2 runtime/purescript.go+35−3 src/CodeGen/IL.hs+28−68 src/CodeGen/IL/Common.hs+58−117 src/CodeGen/IL/Optimizer.hs+2−2 src/CodeGen/IL/Optimizer/TCO.hs+2−2 src/CodeGen/IL/Printer.hs+161−135
app/Main.hs+2−2
@@ -107,8 +107,8 @@ transpile opts baseOutpath jsonFile = do
107107
108108writeRuntimeFiles :: FilePath -> IO ()
109109writeRuntimeFiles baseOutpath = do
110− createDirectoryIfMissing True baseOutpath
111− let runtimeSource = baseOutpath </> "purescript.go"
110+ createDirectoryIfMissing True $ baseOutpath </> "purescript"
111+ let runtimeSource = baseOutpath </> "purescript" </> "purescript.go"
112112 runtimeExists <- doesFileExist runtimeSource
113113 when (not runtimeExists) $ do
114114 B.writeFile runtimeSource $(embedFile "runtime/purescript.go")
runtime/purescript.go+35−3
@@ -2,11 +2,19 @@ package purescript
22
33//go:generate purs --version
44
5−type Any = interface{}
5+import "sync"
6+
7+type Any interface{}
68
79type Fn = func(Any) Any
810type EffFn = func() Any
911
12+type Once = sync.Once
13+
14+type IGNORE_UNUSED_RUNTIME = bool
15+
16+const Undefined = false
17+
1018func Apply(f Any, args ...Any) Any {
1119 result := f
1220 for _, arg := range args {
@@ -16,7 +24,31 @@ func Apply(f Any, args ...Any) Any {
1624 return result
1725}
1826
27+func EffApply(f Any, args ...Any) Any {
28+ fn, _ := f.(EffFn)
29+ return fn()
30+}
31+
1932func Get(dict Any, key string) Any {
20− d, _ := dict.(func(string) Any)
21− return d(key)
33+ d, _ := dict.(map[string]Any)
34+ return d[key]
35+}
36+
37+func SafeGet(dict map[string]Any, key string) Any {
38+ value, ok := dict[key]
39+ if !ok {
40+ panic("Foreign value '" + key + "' not defined")
41+ }
42+ return value
43+}
44+
45+func Contains(dict Any, key string) bool {
46+ d, _ := dict.(map[string]Any)
47+ _, found := d[key]
48+ return found
49+}
50+
51+func Length(arr Any) Any {
52+ a, _ := arr.([]Any)
53+ return len(a)
2254}
src/CodeGen/IL.hs+28−68
@@ -40,6 +40,7 @@ import CodeGen.IL.Optimizer
4040import CodeGen.IL.Printer
4141
4242data DeclType = ModuleDecl | LetDecl | RecLetDecl deriving (Eq)
43+data ImportType = Imported | Ignored
4344
4445-- | Generate code in the simplified intermediate representation for all declarations in a
4546-- module.
@@ -54,8 +55,9 @@ moduleToIL (Module _ coms mn _ imps _ foreigns decls) _ =
5455 do
5556 let usedNames = concatMap getNames decls
5657 let mnLookup = renameImports usedNames imps
57− ilImports <- traverse (importToIL mnLookup) . (\\ (mn : C.primModules)) . (\\ [mn]) $ ordNub $ map snd imps
58− interfaceImport <- importToIL (renameImports [] [(emptyAnn, mn)]) mn
58+ imports <- traverse (importToIL Imported mnLookup) . (\\ (mn : C.primModules)) . (\\ [mn]) $ ordNub $ map snd imps
59+ ignoredImports <- traverse (importToIL Ignored mnLookup) . delete (ModuleName [ProperName C.prim]) . (\\ (mn : C.primModules)) $ ordNub $ map snd imps
60+ interfaceImport <- importToIL Imported (renameImports [] [(emptyAnn, mn)]) mn
5961 let decls' = renameModules mnLookup decls
6062 ilDecls <- mapM (bindToIL ModuleDecl) decls'
6163 optimized <- traverse (traverse (optimize modName')) ilDecls
@@ -63,7 +65,7 @@ moduleToIL (Module _ coms mn _ imps _ foreigns decls) _ =
6365 values = annotValue <$> optimized'
6466 foreigns' = identToIL <$> foreigns
6567 interface = interfaceSource modName values foreigns
66− implHeader = implHeaderSource modName ilImports interfaceImport
68+ implHeader = implHeaderSource modName (imports ++ ignoredImports) interfaceImport
6769 implFooter = implFooterSource modName foreigns
6870 return $ (interface, foreigns', optimized', implHeader, implFooter)
6971 where
@@ -102,24 +104,26 @@ moduleToIL (Module _ coms mn _ imps _ foreigns decls) _ =
102104 then freshModuleName (i + 1) mn' used
103105 else newName
104106
105− -- | Generates C++ code for a module import, binding the required module
107+ -- | Generates IL code for a module import, binding the required module
106108 -- to the alternative
107− importToIL :: M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m Text
108− importToIL mnLookup mn' = do
109+ importToIL :: ImportType -> M.Map ModuleName (Ann, ModuleName) -> ModuleName -> m Text
110+ importToIL t mnLookup mn' = do
109111 let ((_, _, _, _), mnSafe) = fromMaybe (internalError "Missing value in mnLookup") $ M.lookup mn' mnLookup
110112 mname = moduleNameToIL mnSafe
111− pure $ "#include \"" <> mname <> "/" <> mname <> ".h\"\n"
113+ pure $ case t of
114+ Imported -> "import \"" <> mname <> "\"\n"
115+ Ignored -> "type _ = " <> mname <> ".IGNORE_UNUSED_IMPORTS\n"
112116
113117 -- | Replaces the `ModuleName`s in the AST so that the generated code refers to
114118 -- the collision-avoiding renamed module imports.
115119 renameModules :: M.Map ModuleName (Ann, ModuleName) -> [Bind Ann] -> [Bind Ann]
116120 renameModules mnLookup binds =
117− let (f, _, _) = everywhereOnValues id goExpr goBinder
121+ let (f, _, _) = everywhereOnValues id ilExpr goBinder
118122 in map f binds
119123 where
120− goExpr :: Expr a -> Expr a
121− goExpr (Var ann q) = Var ann (renameQual q)
122− goExpr e = e
124+ ilExpr :: Expr a -> Expr a
125+ ilExpr (Var ann q) = Var ann (renameQual q)
126+ ilExpr e = e
123127 goBinder :: Binder a -> Binder a
124128 goBinder (ConstructorBinder ann q1 q2 bs) = ConstructorBinder ann (renameQual q1) (renameQual q2) bs
125129 goBinder b = b
@@ -153,39 +157,8 @@ moduleToIL (Module _ coms mn _ imps _ foreigns decls) _ =
153157 il <- valueToIL val
154158 pure $ AST.Function Nothing (Just $ identToIL ident) [] (AST.Block Nothing [AST.Return Nothing il])
155159 nonRecToIL RecLetDecl (ss, _, _, _) ident val = do
156− il <- valueToIL val
157− pure $
158− let retainedName = identToIL ident
159− retained = AST.Var Nothing $ retainedName
160− unretainedName = retainedName <> unretainedSuffix
161− unretained = AST.Var Nothing $ unretainedName
162− boxed = AST.Var Nothing . -- Note: prevents optimizer from eliminating this
163− prettyPrintIL1 $
164− AST.VariableIntroduction
165− Nothing
166− retainedName
167− (Just unretained)
168− alias = AST.Var Nothing $ "auto& " <> retainedName <> " = " <> unretainedName
169− in
170− case il of
171− AST.Function _ name args (AST.Block Nothing ils) ->
172− AST.Assignment Nothing
173− retained
174− (AST.Function Nothing
175− name
176− args
177− (AST.Block Nothing (boxed : ils)))
178− _ ->
179− AST.Assignment Nothing
180− retained
181− (AST.App Nothing
182− (AST.Function Nothing
183− Nothing
184− []
185− (AST.Block Nothing ([ alias
186− , AST.Return Nothing il
187− ])))
188− [])
160+ ilExpr <- valueToIL val
161+ pure $ AST.Assignment Nothing (AST.Var Nothing $ identToIL ident) ilExpr
189162 nonRecToIL _ (ss, _, _, _) ident val = do
190163 il <- valueToIL val
191164 pure $ AST.VariableIntroduction Nothing (identToIL ident) (Just il)
@@ -222,9 +195,11 @@ moduleToIL (Module _ coms mn _ imps _ foreigns decls) _ =
222195 valueToIL e@App{} = do
223196 let (f, args) = unApp e []
224197 args' <- mapM valueToIL args
198+ fn <- valueToIL f
225199 case f of
226200 Var (_, _, _, Just IsNewtype) _ -> return (head args')
227− _ -> flip (foldl (\fn a -> AST.App Nothing fn [a])) args' <$> valueToIL f
201+ _ -> return $ AST.App Nothing fn args'
202+ -- _ -> flip (foldl (\fn a -> AST.App Nothing fn [a])) args' <$> valueToIL f
228203 where
229204 unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann])
230205 unApp (App _ val arg) args = unApp val (arg : args)
@@ -247,30 +222,14 @@ moduleToIL (Module _ coms mn _ imps _ foreigns decls) _ =
247222 bindersToIL ss binders vals
248223 valueToIL (Let _ ds val) = do
249224 let recurs = concatMap getNames $ filter isRec ds
250− recurDs = (\v -> AST.Var Nothing $ "boxed::recur " <> identToIL v) <$> recurs
251− recurDsWeak = (\v -> AST.Var
252− Nothing
253− ("boxed::recur::weak " <> identToIL v <> unretainedSuffix <> "(" <> identToIL v <> ")")
254− ) <$> recurs
255− mutualRecurWarning = if any isMutRec $ filter isRec ds
256− then [AST.Var Nothing "#pragma message(\"Mutually recursive lets will cause retain cycles (memory leaks)\") //"]
257− else []
225+ recurDs = (\v -> AST.VariableIntroduction Nothing (identToIL v) Nothing) <$> recurs
258226 ds' <- concat <$> mapM (bindToIL LetDecl) ds
259227 ret <- valueToIL val
260− return $
261− AST.App Nothing
262− (AST.Function Nothing
263− Nothing
264− []
265− (AST.Block Nothing (recurDs ++ recurDsWeak ++ mutualRecurWarning ++ ds' ++ [AST.Return Nothing ret])))
266− []
228+ return $ AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing (recurDs ++ ds' ++ [AST.Return Nothing ret]))) []
267229 where
268230 isRec :: Bind Ann -> Bool
269231 isRec (Rec _) = True
270− isRec _ = False
271− isMutRec :: Bind Ann -> Bool
272− isMutRec b | (length . nub $ getNames b) > 1 = True
273− | otherwise = False
232+ isRec _ = False
274233 valueToIL (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) = error "IsNewtype"
275234 valueToIL (Constructor _ _ (ProperName ctor) fields) =
276235 let body = AST.ObjectLiteral Nothing $ (mkString ctor, AST.BooleanLiteral Nothing True) :
@@ -300,9 +259,9 @@ moduleToIL (Module _ coms mn _ imps _ foreigns decls) _ =
300259 -- | Generate code in the simplified intermediate representation for a reference to a
301260 -- variable that may have a qualified name.
302261 qualifiedToIL :: (a -> Ident) -> Qualified a -> AST
303− qualifiedToIL f (Qualified (Just (ModuleName [ProperName mn'])) a) | mn' == C.prim = AST.Var Nothing . runIdent $ f a
304− qualifiedToIL f (Qualified (Just mn') a) = AST.Indexer Nothing (AST.Var Nothing . identToIL $ f a) (AST.Var Nothing (moduleNameToIL mn'))
305− qualifiedToIL f (Qualified _ a) = AST.Var Nothing $ identToIL (f a)
262+ qualifiedToIL f (Qualified (Just (ModuleName [ProperName mn'])) a) | mn' == C.prim = AST.Var Nothing . identToIL $ f a
263+ qualifiedToIL f (Qualified (Just mn') a) | mn /= mn' = AST.Indexer Nothing (AST.Var Nothing . identToIL $ f a) (AST.Var Nothing (moduleNameToIL mn'))
264+ qualifiedToIL f (Qualified _ a) = AST.Indexer Nothing (AST.Var Nothing . identToIL $ f a) (AST.Var Nothing "")
306265
307266 -- foreignIdent :: Ident -> AST
308267 -- foreignIdent ident = accessorString (mkString $ runIdent ident) (AST.Var Nothing "$foreign")
@@ -414,8 +373,9 @@ emptyAnn = (SourceSpan "" (SourcePos 0 0) (SourcePos 0 0), [], Nothing, Nothing)
414373
415374arrayLength :: AST -> AST
416375arrayLength a = AST.App Nothing (AST.Var Nothing arrayLengthFn) [a]
376+-- arrayLength a = AST.Var Nothing (arrayLengthFn <> "(" <> prettyPrintIL1 a <> ")")
417377
418378freshName' :: MonadSupply m => m Text
419379freshName' = do
420380 name <- freshName
421− return $ T.replace "$" "_Local_" name
381+ return $ T.replace "$" "𝕡" name
src/CodeGen/IL/Common.hs+58−117
@@ -11,57 +11,56 @@ import qualified Data.Text as T
1111import Language.PureScript.Crash
1212import Language.PureScript.Names
1313
14+import qualified Language.PureScript.Constants as C
15+
1416moduleNameToIL :: ModuleName -> Text
1517moduleNameToIL (ModuleName pns) =
1618 let name = T.intercalate "_" (runProperName `map` pns)
1719 in if nameIsILBuiltIn name then ("_" <> name <> "_") else name
1820
19−-- | Convert an 'Ident' into a valid C++ identifier:
21+-- | Convert an 'Ident' into a valid IL identifier:
2022--
2123-- * Alphanumeric characters are kept unmodified.
2224--
23−-- * Reserved C++ identifiers are wrapped with '_'.
25+-- * Reserved IL identifiers are wrapped with '_'.
2426--
2527identToIL :: Ident -> Text
2628identToIL UnusedIdent = unusedName
2729identToIL (Ident "$__unused") = unusedName
30+identToIL (Ident name) | name == C.undefined = undefinedName
2831identToIL (Ident name) = properToIL name
2932identToIL (GenIdent _ _) = internalError "GenIdent in identToIL"
3033
34+undefinedName :: Text
35+undefinedName = "Undefined"
36+
3137unusedName :: Text
32−unusedName = "_Unused_"
38+unusedName = "_"
3339
3440properToIL :: Text -> Text
3541properToIL name
3642 | nameIsILReserved name || nameIsILBuiltIn name || prefixIsReserved name = "_" <> name <> "_"
3743 | otherwise = T.concatMap identCharToText name
3844
39−-- | Test if a string is a valid AST identifier without escaping.
40−identNeedsEscaping :: Text -> Bool
41−identNeedsEscaping s = s /= properToIL s || T.null s
42−
4345-- | Attempts to find a human-readable name for a symbol, if none has been specified returns the
4446-- ordinal value.
4547identCharToText :: Char -> Text
4648identCharToText c | isAlphaNum c = T.singleton c
4749identCharToText '_' = "_"
4850identCharToText '\'' = "_Prime_"
49−identCharToText '$' = "$"
50−identCharToText c = "_Code_Point_" <> T.pack (show (ord c))
51+-- identCharToText '$' = "𝕤"
52+identCharToText c = "𝕦" <> T.pack (show (ord c))
5153
52−-- | Checks whether an identifier name is reserved in C++.
54+-- | Checks whether an identifier name is reserved in IL.
5355nameIsILReserved :: Text -> Bool
5456nameIsILReserved name =
5557 name `elem` ilAnyReserved
5658
57−-- | Checks whether a name matches a built-in value in C++.
59+-- | Checks whether a name matches a built-in value in IL.
5860nameIsILBuiltIn :: Text -> Bool
5961nameIsILBuiltIn name =
6062 name `elem`
61− [ "final"
62− , "override"
63− , "posix"
64− , "std"
63+ [
6564 ]
6665
6766ilAnyReserved :: [Text]
@@ -73,135 +72,80 @@ ilAnyReserved =
7372
7473ilKeywords :: [Text]
7574ilKeywords =
76− [ "alignas"
77− , "alignof"
78− , "and"
79− , "and_eq"
80− , "asm"
81− , "assert"
82− , "atomic_cancel"
83− , "atomic_commit"
84− , "atomic_noexcept"
85− , "auto"
86− , "bitand"
87− , "bitor"
88− , "bool"
89− , "break"
75+ [ "break"
9076 , "case"
91− , "catch"
92− , "char"
93− , "char16_t"
94− , "char32_t"
95− , "class"
96− , "compl"
97− , "concept"
77+ , "chan"
9878 , "const"
99− , "constexpr"
100− , "const_cast"
10179 , "continue"
102− , "concept"
103− , "decltype"
10480 , "default"
105− , "delete"
106− , "do"
107− , "double"
108− , "dynamic_cast"
81+ , "defer"
10982 , "else"
110− , "enum"
111− , "explicit"
112− , "export"
113− , "extern"
114− , "false"
115− , "float"
83+ , "fallthrough"
11684 , "for"
117− , "friend"
85+ , "func"
86+ , "go"
11887 , "goto"
11988 , "if"
12089 , "import"
121− , "inline"
122− , "int"
123− , "long"
124− , "module"
125− , "mutable"
126− , "namespace"
127− , "new"
128− , "noexcept"
129− , "not"
130− , "not_eq"
131− , "nullptr"
132− , "nullptr_t"
133− , "operator"
134− , "or"
135− , "or_eq"
136− , "private"
137− , "protected"
138− , "public"
139− , "register"
140− , "reinterpret_cast"
141− , "requires"
90+ , "interface"
91+ , "map"
92+ , "package"
93+ , "range"
14294 , "return"
143− , "short"
144− , "signed"
145− , "sizeof"
146− , "static"
147− , "static_assert"
148− , "static_cast"
95+ , "select"
14996 , "struct"
15097 , "switch"
151− , "synchronized"
152− , "template"
153− , "this"
154− , "thread_local"
155− , "throw"
156− , "true"
157− , "try"
158− , "typedef"
159− , "typeid"
160− , "typename"
161− , "typeof"
162− , "union"
163− , "unsigned"
164− , "using"
165− , "virtual"
166− , "void"
167− , "volatile"
168− , "wchar_t"
169− , "while"
170− , "xor"
171− , "xor_eq"
98+ , "type"
99+ , "var"
172100 ]
173101
174102prefixIsReserved :: Text -> Bool
175103prefixIsReserved name =
176104 any (`T.isPrefixOf` name)
177− [ "__"
105+ [
178106 ]
179107
180108ilLiterals :: [Text]
181109ilLiterals =
182− [ "box"
183− , "boxed"
184− , "copy"
185− , "errno"
186− , "peek"
187− , "purescript"
188− , "runtime_error"
189− , "setjmp"
110+ [ "init"
111+ , "nil"
112+ , "int"
113+ , "int8"
114+ , "int16"
115+ , "int32"
116+ , "int64"
117+ , "uint"
118+ , "uint8"
119+ , "uint16"
120+ , "uint32"
121+ , "uint64"
122+ , "uintptr"
123+ , "float32"
124+ , "float64"
125+ , "complex64"
126+ , "complex128"
127+ , "byte"
128+ , "rune"
190129 , "string"
191− , "unbox"
192130 ]
193131
132+withPrefix :: Text -> Text
133+withPrefix s = "PS__" <> s
134+
135+anyType :: Text
136+anyType = "Any"
137+
194138dictType :: Text
195−dictType = "dict_t"
139+dictType = "map[string]Any"
196140
197141arrayType :: Text
198−arrayType = "array_t"
142+arrayType = "[]Any"
199143
200144int :: Text
201145int = "int"
202146
203147float :: Text
204−float = "double"
148+float = "float64"
205149
206150bool :: Text
207151bool = "bool"
@@ -210,13 +154,10 @@ string :: Text
210154string = "string"
211155
212156unbox :: Text -> Text
213−unbox t = "unbox<" <> t <> ">"
157+unbox t = ".(" <> t <> ")"
214158
215159arrayLengthFn :: Text
216−arrayLengthFn = "array_length"
217−
218−unretainedSuffix :: Text
219−unretainedSuffix = "_Weak_"
160+arrayLengthFn = "Length"
220161
221162tcoLoop :: Text
222163tcoLoop = "_TCO_Loop_"
src/CodeGen/IL/Optimizer.hs+2−2
@@ -12,7 +12,7 @@ import Language.PureScript.CoreImp.Optimizer.Inliner hiding (inlineUnsafeCoerce,
1212import Language.PureScript.CoreImp.Optimizer.Unused
1313import Language.PureScript.PSString (PSString, decodeString)
1414
15−import CodeGen.IL.Common (unusedName)
15+import CodeGen.IL.Common (undefinedName, unusedName)
1616import CodeGen.IL.Optimizer.TCO
1717
1818import qualified Language.PureScript.Constants as C
@@ -56,7 +56,7 @@ inlineUnsafePartial = everywhereTopDown convert where
5656 | unsafePartial == C.unsafePartial && partialUnsafe == C.partialUnsafe
5757 -- Apply to undefined here, the application should be optimized away
5858 -- if it is safe to do so
59− = App ss comp [ Var ss C.undefined ]
59+ = App ss comp [ Var ss undefinedName ]
6060 convert other = other
6161
6262inlineUnsafeCoerce :: AST -> AST
src/CodeGen/IL/Optimizer/TCO.hs+2−2
@@ -93,11 +93,11 @@ tco mn = everywhere convert where
9393 concatMap (\arg -> [ VariableIntroduction rootSS (tcoVar arg) Nothing
9494 , Assignment rootSS (Var rootSS (tcoVar arg)) (Var rootSS (copyVar arg)) ]) (outerArgs ++ innerArgs) ++
9595 -- [ VariableIntroduction rootSS (blockDecl <> tcoDone) Nothing
96− [ Var rootSS ("bool " <> tcoDone <> " = false")
96+ [ Var rootSS (tcoDone <> " := false")
9797 -- , Assignment rootSS (Var rootSS tcoDone) (BooleanLiteral rootSS False)
9898 -- , Assignment rootSS (Var rootSS tcoDone) (Var rootSS "NO")
9999 , VariableIntroduction rootSS tcoResult Nothing
100− , Assignment rootSS (Var rootSS ("const auto " <> tcoLoop)) (Function rootSS (Just tcoLoop) (outerArgs ++ innerArgs) (Block rootSS [loopify js]))
100+ , Assignment rootSS (Var rootSS ("var " <> tcoLoop)) (Function rootSS (Just tcoLoop) (outerArgs ++ innerArgs) (Block rootSS [loopify js]))
101101 -- , While rootSS (Binary Nothing EqualTo (Var rootSS tcoDone) (BooleanLiteral Nothing False))
102102 , While rootSS (Unary Nothing Not (Var rootSS tcoDone))
103103 (Block rootSS
src/CodeGen/IL/Printer.hs+161−135
@@ -15,7 +15,6 @@ import Control.Arrow ((<+>))
1515import Control.Monad (forM, mzero)
1616import Control.Monad.State (StateT, evalStateT)
1717import Control.PatternArrows
18−import Data.Char (isAscii)
1918import Data.List (filter, (\\))
2019import qualified Control.Arrow as A
2120
@@ -49,26 +48,23 @@ literals = mkPattern' match'
4948 match (BooleanLiteral _ True) = return $ emit "true"
5049 match (BooleanLiteral _ False) = return $ emit "false"
5150 match (ArrayLiteral _ xs) = mconcat <$> sequence
52− [ return . emit $ arrayType <> "{ "
51+ [ return . emit $ arrayType <> "{"
5352 , intercalate (emit ", ") <$> forM xs prettyPrintIL'
54− , return $ emit " }"
53+ , return $ emit "}"
5554 ]
5655 -- match (ObjectLiteral _ []) = return $ emit "std::initializer_list<std::pair<const string, boxed>>{}"
5756 match (ObjectLiteral _ ps) = mconcat <$> sequence
58− [ return . emit $ dictType <> "{\n"
57+ [ return . emit $ dictType <> "{"
5958 , withIndent $ do
6059 ils <- forM ps $ \(key, value) -> do
6160 value' <- prettyPrintIL' value
62− return $ emit "{ " <> objectPropertyToString key <> value' <> emit " }"
63− indentString <- currentIndent
64− return $ intercalate (emit ",\n") $ map (indentString <>) ils
65− , return $ emit "\n"
66− , currentIndent
61+ return $ objectPropertyToString key <> value'
62+ return $ intercalate (emit " ") $ map (<> emit ",") ils
6763 , return $ emit "}"
6864 ]
6965 where
7066 objectPropertyToString :: (Emit gen) => PSString -> gen
71− objectPropertyToString s = emit $ stringLiteral s <> ", "
67+ objectPropertyToString s = emit $ stringLiteral s <> ": "
7268 match (Block _ sts) = mconcat <$> sequence
7369 [ return $ emit "{\n"
7470 , withIndent $ prettyStatements sts
@@ -78,7 +74,7 @@ literals = mkPattern' match'
7874 ]
7975 match (Var _ ident) = return $ emit ident
8076 match (VariableIntroduction _ ident value) = mconcat <$> sequence
81− [ return $ emit $ "boxed " <> ident
77+ [ return . emit $ varDecl <> " " <> ident <> " " <> anyType
8278 , maybe (return mempty) (fmap (emit " = " <>) . prettyPrintIL') value
8379 ]
8480 match (Assignment _ target value) = mconcat <$> sequence
@@ -87,13 +83,20 @@ literals = mkPattern' match'
8783 , prettyPrintIL' value
8884 ]
8985 match (App _ val []) = mconcat <$> sequence
90− [ prettyPrintIL' val
91− , return $ emit "()"
86+ [ return $ emit "EffApply("
87+ , prettyPrintIL' val
88+ , return $ emit ")"
89+ ]
90+ match (App _ (Var _ fn) [arg]) | fn == arrayLengthFn = mconcat <$> sequence
91+ [ return $ emit arrayLengthFn
92+ , return $ emit "("
93+ , prettyPrintIL' arg
94+ , return $ emit ")"
9295 ]
93− match (App ss (App _ (App _ (Indexer _ (Var _ fn) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod)]) [x]) [y])
96+ match (App ss (Indexer _ (Var _ fn) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod), x, y])
9497 | fnMod == dictMod
9598 , dictMod == C.dataEq || dictMod == C.dataSemiring || dictMod == C.dataRing ||
96− dictMod == C.dataEuclideanRing || dictMod == C.dataHeytingAlgebra
99+ dictMod == C.dataEuclideanRing || dictMod == C.dataHeytingAlgebra || dictMod == C.dataOrd
97100 , Just op <- renderOp fn
98101 , Just t <- unboxType dict
99102 = mconcat <$> sequence
@@ -101,130 +104,151 @@ literals = mkPattern' match'
101104 , return $ emit op
102105 , return $ emit $ unbox' t y
103106 ]
104− match (App _ (App _ (Indexer _ (Var _ fn) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod)]) [n])
107+ match (App _ (Indexer _ (Var _ fn) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod), n])
105108 | fnMod == dictMod
106109 , dictMod == C.dataRing
107110 , fn == C.negate
108111 , Just t <- unboxType dict
109112 = mconcat <$> sequence
110− [ return $ emit "-"
113+ [ return $ emit "-("
111114 , return $ emit $ unbox' t n
115+ , return $ emit ")"
112116 ]
113− match (App _ (App _ (Indexer _ (Var _ fn) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod)]) [n])
117+ match (App _ (Indexer _ (Var _ fn) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod), n])
114118 | fnMod == dictMod
115119 , dictMod == C.dataHeytingAlgebra
116120 , fn == properToIL C.not
117121 , Just t <- unboxType dict
118122 = mconcat <$> sequence
119− [ return $ emit "!"
123+ [ return $ emit "!("
120124 , return $ emit $ unbox' t n
125+ , return $ emit ")"
121126 ]
122127 match (App _ val args) = mconcat <$> sequence
123− [ prettyPrintIL' val
124− , return $ emit "("
128+ [ return $ emit "Apply("
129+ , prettyPrintIL' val
130+ , return $ emit ", "
125131 , intercalate (emit ", ") <$> forM args prettyPrintIL'
126132 , return $ emit ")"
127133 ]
128134 match (Function _ (Just name) [] (Block _ [Return _ ret]))
129− | isLiteral ret = mconcat <$> sequence
130− [ return $ emit "auto "
131− , return $ emit name
132− , return $ emit "() -> const boxed& "
135+ | isComplexLiteral ret = mconcat <$> sequence
136+ [ return $ emit "\n"
137+ , return . emit $ varDecl <> " " <> initName name <> " Once\n"
138+ , prettyPrintIL' $ VariableIntroduction Nothing (valueName name) Nothing
139+ , return $ emit "\n\n"
140+ , return $ emit "func "
141+ , return . emit $ withPrefix name
142+ , return . emit $ "() " <> anyType <> " "
133143 , return $ emit "{\n"
134144 , withIndent $ do
135− indentString <- currentIndent
136− return $ indentString <> emit staticValueBegin
145+ indentString <- currentIndent
146+ return $ indentString <> (emit $ initName name <> ".Do(func() {\n") <>
147+ indentString <> indentString <> (emit $ valueName name <> " = ")
137148 , withIndent $ do
138149 case ret of
139150 Function _ Nothing args body -> mconcat <$> sequence
140− [ return $ emit "[]("
141− , return $ emit $ intercalate ", " (renderArg <$> args)
142− , return $ emit ") -> boxed "
151+ [ return $ emit "func("
152+ , return . emit $ intercalate ", " (renderArg anyType <$> args)
153+ , return . emit $ ") " <> anyType <> " "
143154 , prettyPrintIL' body
144155 ]
145156 _ -> do
146157 prettyPrintIL' ret
147− , return $ emit ";\n"
158+ , return $ emit "\n"
148159 , withIndent $ do
149− indentString <- currentIndent
150− return $ indentString <> emit staticValueEnd
151− , return $ emit "\n}"
160+ indentString <- currentIndent
161+ return $ indentString <> (emit $ "})\n" <> "return " <> valueName name <>"\n")
162+ , return $ emit "}\n\n"
152163 ]
153164 match (Function _ (Just name) [] ret) = mconcat <$> sequence
154− [ return $ emit "auto "
155− , return $ emit name
156− , return $ emit "() -> boxed "
165+ [ return $ emit "func "
166+ , return . emit $ withPrefix name
167+ , return . emit $ "() " <> anyType <> " "
157168 , prettyPrintIL' ret
158169 ]
159− match (Function _ name args ret) = mconcat <$> sequence
160− [ return $ emit captures
161− , return $ emit "("
162− , return $ emit $ intercalate ", " (render <$> args)
163− , return $ emit ") -> boxed "
170+ match (Function _ _ args ret) = mconcat <$> sequence
171+ [ return $ emit "func("
172+ , return . emit $ intercalate ", " (renderArg anyType <$> args)
173+ , return . emit $ ") " <> anyType <> " "
164174 , prettyPrintIL' ret
165175 ]
166− where
167− (captures, render)
168− | name == Just tcoLoop = ("[&]", renderArgByVal)
169− | otherwise = ("[=]", renderArg)
170− match (Indexer _ prop@(Var _ name) val) = mconcat <$> sequence
176+ match (Indexer _ (Var _ name) (Var _ "")) = mconcat <$> sequence
177+ [ prettyPrintIL' (Var Nothing $ withPrefix name)
178+ , return $ emit "()"
179+ ]
180+ match (Indexer _ (Var _ name) val) = mconcat <$> sequence
171181 [ prettyPrintIL' val
172− , return $ emit "::"
173− , prettyPrintIL' prop
182+ , return $ emit "."
183+ , prettyPrintIL' (Var Nothing $ withPrefix name)
174184 , return $ emit "()"
175185 ]
176186 match (Indexer _ prop val) = mconcat <$> sequence
177− [ prettyPrintIL' val
178− , return $ emit "["
187+ [ return $ emit "Get("
188+ , prettyPrintIL' val
189+ , return $ emit ", "
179190 , prettyPrintIL' prop
180− , return $ emit "]"
191+ , return $ emit ")"
181192 ]
182193 match (InstanceOf _ val ty) = mconcat <$> sequence
183− [ return . emit $ unbox' dictType val
184− , return $ emit ".contains("
194+ [ return $ emit "Contains("
195+ , prettyPrintIL' val
196+ , return $ emit ", "
185197 , prettyPrintIL' ty
186198 , return $ emit ")"
187199 ]
188200 match (While _ cond sts) = mconcat <$> sequence
189− [ return $ emit "while ("
201+ [ return $ emit "for "
190202 , prettyPrintIL' cond
191− , return $ emit ") "
203+ , return $ emit " "
192204 , prettyPrintIL' sts
193205 ]
194206 match (For _ ident start end sts) = mconcat <$> sequence
195− [ return $ emit $ "for (boxed " <> ident <> " = "
207+ [ return $ emit $ "for var " <> ident <> " = "
196208 , prettyPrintIL' start
197209 , return $ emit $ "; " <> ident <> " < "
198210 , prettyPrintIL' end
199− , return $ emit $ "; " <> ident <> "++) "
211+ , return $ emit $ "; " <> ident <> "++ "
200212 , prettyPrintIL' sts
201213 ]
202214 match (ForIn _ ident obj sts) = mconcat <$> sequence
203− [ return $ emit $ "for (boxed " <> ident <> " in "
215+ [ return $ emit $ "for var " <> ident <> " in "
204216 , prettyPrintIL' obj
205− , return $ emit ") "
217+ , return $ emit " "
206218 , prettyPrintIL' sts
207219 ]
220+ match (IfElse _ (Binary _ EqualTo cond (BooleanLiteral Nothing True)) thens elses)
221+ | (App ss (Indexer _ (Var _ _) (Var _ fnMod)) [Indexer _ (Var _ dict) (Var _ dictMod), x, y]) <- cond
222+ , fnMod == dictMod
223+ , dictMod == C.dataEq || dictMod == C.dataOrd
224+ , Just _ <- unboxTypeInt dict
225+ = mconcat <$> sequence
226+ [ return $ emit "if "
227+ , prettyPrintIL' cond
228+ , return $ emit " "
229+ , prettyPrintIL' thens
230+ , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
231+ ]
208232 match (IfElse _ (Binary _ EqualTo cond (BooleanLiteral Nothing True)) thens elses) = mconcat <$> sequence
209− [ return $ emit "if ("
233+ [ return $ emit "if "
210234 , return $ emit $ unbox' "bool" cond
211− , return $ emit ") "
235+ , return $ emit " "
212236 , prettyPrintIL' thens
213237 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
214238 ]
215239 match (IfElse _ (Binary _ EqualTo cond (BooleanLiteral Nothing False)) thens elses) = mconcat <$> sequence
216− [ return $ emit "if (!("
240+ [ return $ emit "if !("
217241 , return $ emit $ unbox' "bool" cond
218− , return $ emit ")) "
242+ , return $ emit ") "
219243 , prettyPrintIL' thens
220244 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
221245 ]
222246 match (IfElse _ (Binary _ EqualTo x y@(NumericLiteral _ n)) thens elses) = mconcat <$> sequence
223− [ return $ emit "if ("
247+ [ return $ emit "if "
224248 , return $ emit $ unbox' t x
225249 , return $ emit $ " == "
226250 , prettyPrintIL' y
227− , return $ emit ") "
251+ , return $ emit " "
228252 , prettyPrintIL' thens
229253 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
230254 ]
@@ -232,18 +256,18 @@ literals = mkPattern' match'
232256 t | Left _ <- n = int
233257 | Right _ <- n = float
234258 match (IfElse _ (Binary _ EqualTo a b@StringLiteral{}) thens elses) = mconcat <$> sequence
235− [ return $ emit "if ("
259+ [ return $ emit "if "
236260 , return $ emit $ unbox' string a
237261 , return $ emit $ " == "
238262 , prettyPrintIL' b
239− , return $ emit ") "
263+ , return $ emit " "
240264 , prettyPrintIL' thens
241265 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
242266 ]
243267 match (IfElse _ cond thens elses) = mconcat <$> sequence
244− [ return $ emit "if ("
268+ [ return $ emit "if "
245269 , prettyPrintIL' cond
246− , return $ emit ") "
270+ , return $ emit " "
247271 , prettyPrintIL' thens
248272 , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
249273 ]
@@ -251,11 +275,12 @@ literals = mkPattern' match'
251275 [ return $ emit "return "
252276 , prettyPrintIL' value
253277 ]
254− match (ReturnNoResult _) = return $ emit "return undefined"
278+ match (ReturnNoResult _) = return . emit $ "return " <> undefinedName
255279 -- match (Throw _ _) = return mempty
256280 match (Throw _ value) = mconcat <$> sequence
257− [ return $ emit "THROW_("
281+ [ return $ emit "panic("
258282 , return $ emit "\"PatternMatchFailure: \""
283+ , return $ emit " + "
259284 , prettyPrintIL' value
260285 , return $ emit ")"
261286 ]
@@ -330,11 +355,17 @@ isLiteral ObjectLiteral{} = True
330355isLiteral ArrayLiteral{} = True
331356isLiteral _ = False
332357
358+isComplexLiteral :: AST -> Bool
359+-- isComplexLiteral Function{} = True
360+isComplexLiteral ObjectLiteral{} = True
361+isComplexLiteral ArrayLiteral{} = True
362+isComplexLiteral _ = False
363+
333364prettyStatements :: (Emit gen) => [AST] -> StateT PrinterState Maybe gen
334365prettyStatements sts = do
335366 ils <- forM sts prettyPrintIL'
336367 indentString <- currentIndent
337− return $ intercalate (emit "\n") $ map ((<> emit ";") . (indentString <>)) ils
368+ return $ intercalate (emit "\n") $ map (indentString <>) ils
338369
339370-- | Generate a pretty-printed string representing a collection of C++ expressions at the same indentation level
340371prettyPrintILWithSourceMaps :: [AST] -> (Text, [SMap])
@@ -383,15 +414,12 @@ prettyPrintIL1 :: AST -> Text
383414prettyPrintIL1 = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyPrintIL'
384415
385416stringLiteral :: PSString -> Text
386−stringLiteral pss | Just s <- decodeString pss =
387− (if T.all isAscii s
388− then ""
389− else ("u8")) <> stringLiteral' s
417+stringLiteral pss | Just s <- decodeString pss = stringLiteral' s
390418 where
391419 stringLiteral' :: Text -> Text
392420 stringLiteral' s = "\"" <> T.concatMap encodeChar s <> "\""
393421 encodeChar :: Char -> Text
394− encodeChar '\0' = "\\0"
422+ encodeChar '\0' = "\\x00"
395423 encodeChar '\b' = "\\b"
396424 encodeChar '\t' = "\\t"
397425 encodeChar '\n' = "\\n"
@@ -407,13 +435,14 @@ unbox' :: Text -> AST -> Text
407435unbox' _ v@(NumericLiteral{}) = prettyPrintIL1 v
408436unbox' _ v@(BooleanLiteral{}) = prettyPrintIL1 v
409437unbox' _ v@(StringLiteral{}) = prettyPrintIL1 v
410−unbox' t v = unbox t <> "(" <> prettyPrintIL1 v <> ")"
438+unbox' t v = "(" <> prettyPrintIL1 v <> ")" <> unbox t -- unbox t <> "(" <> prettyPrintIL1 v <> ")"
411439
412440unboxType :: Text -> Maybe Text
413441unboxType t
414442 | t == C.eqInt ||
415443 t == C.semiringInt ||
416− t == C.ringInt
444+ t == C.ringInt ||
445+ t == C.ordInt
417446 = Just int
418447 | t == C.semiringNumber ||
419448 t == C.ringNumber ||
@@ -423,10 +452,23 @@ unboxType t
423452 = Just bool
424453 | otherwise = Nothing
425454
455+unboxTypeInt :: Text -> Maybe Text
456+unboxTypeInt t
457+ | t == C.eqInt ||
458+ t == C.semiringInt ||
459+ t == C.ringInt ||
460+ t == C.ordInt
461+ = Just int
462+ | otherwise = Nothing
463+
426464renderOp :: Text -> Maybe Text
427465renderOp op
428466 | op == C.eq = Just " == "
429467 | op == C.notEq = Just " != "
468+ | op == C.lessThan = Just " < "
469+ | op == C.lessThanOrEq = Just " <= "
470+ | op == C.greaterThan = Just " > "
471+ | op == C.greaterThanOrEq = Just " >= "
430472 | op == C.add = Just " + "
431473 | op == C.sub = Just " - "
432474 | op == C.mul = Just " * "
@@ -436,29 +478,22 @@ renderOp op
436478 | otherwise = Nothing
437479
438480interfaceSource :: Text -> [(Text,Bool)] -> [Ident] -> Text
439−interfaceSource mn values foreigns =
440− let foreigns' = identToIL <$> foreigns
441− valueNames = fst <$> values
442− values' = filter ((`notElem` foreigns') . fst) values ++
443− zip (foreigns' \\ valueNames) (repeat True)
444− in
445− "// Generated by psil compiler\n\n" <>
446− "#ifndef " <> mn <> "_H\n" <>
447− "#define " <> mn <> "_H\n\n" <>
448− "#include \"purescript.h\"\n\n" <>
449− "namespace " <> mn <> " {\n\n" <>
450− "using namespace purescript;\n\n" <>
451− (T.concat $ (\(export, static) ->
452− let rty = if static then "const boxed&" else "boxed" in
453− "auto " <> export <> "() -> " <> rty <> ";\n") <$> values') <> "\n" <>
454− "} // end namespace " <> mn <> "\n\n" <>
455− "#endif // " <> mn <> "_H\n\n"
481+interfaceSource _ _ _ = ""
456482
457483implHeaderSource :: Text -> [Text] -> Text -> Text
458−implHeaderSource mn imports interfaceImport =
459− T.concat imports <> "\n"<>
460− interfaceImport <> "\n\n" <>
461− "namespace " <> mn <> " {\n\n"
484+implHeaderSource mn imports _ =
485+ "// Code generated by psgo. DO NOT EDIT.\n\n" <>
486+ "package " <> (if mn == "Main" then "main" else mn) <> "\n\n" <>
487+ "import . \"purescript\"\n" <>
488+ (if mn == "Main"
489+ then "import \"purescript_ffi\"\n"
490+ else "") <>
491+ T.concat imports <> "\n" <>
492+ "type IGNORE_UNUSED_IMPORTS = bool\n" <>
493+ "type _ = IGNORE_UNUSED_RUNTIME\n" <>
494+ (if mn == "Main"
495+ then "\nconst _ = purescript_ffi.Loader\n\n"
496+ else "\n")
462497
463498implFooterSource :: Text -> [Ident] -> Text
464499implFooterSource mn foreigns =
@@ -466,50 +501,41 @@ implFooterSource mn foreigns =
466501 (if null foreigns
467502 then ""
468503 else ("// Foreign values\n\n" <>
469− "DEFINE_FOREIGN_DICTIONARY_AND_ACCESSOR()\n\n" <>
470− (T.concat $ (\foreign' -> "auto " <>
471− identToIL foreign' <>
472− "() -> const boxed& { " <>
473− staticValueBegin <>
474− foreignDict <> "().at(" <>
475− (stringLiteral . mkString $ runIdent foreign') <> "); " <>
476− staticValueEnd <>
477− " };\n") <$> foreigns) <>
478− "\n")) <>
479− "} // end namespace " <> mn <>
480− "\n\n" <>
504+ "var " <> foreignDict <> " = " <> dictType <> "{}\n\n" <>
505+ (T.concat $ (\foreign' ->
506+ let name = identToIL foreign' in
507+ varDecl <> " " <> initName name <> " Once\n" <>
508+ varDecl <> " " <> valueName name <> " " <> anyType <> "\n\n" <>
509+ "func " <>
510+ withPrefix name <>
511+ "() Any { \n" <>
512+ " " <> initName name <> ".Do(func() {\n" <>
513+ " " <> valueName name <> " = " <>
514+ "SafeGet(" <> foreignDict <> ", " <>
515+ (stringLiteral $ mkString name) <> ")\n" <>
516+ " })\n" <>
517+ " return " <> valueName name <> "\n" <>
518+ "}\n\n") <$> foreigns))) <>
481519 if mn == "Main" then mainSource else "\n"
482520 where
483521 mainSource :: Text
484522 mainSource = "\
485− \int main(int argc, const char * argv[]) {\n\
486− \ Main::main()();\n\
487− \ return 0;\n\
523+ \func main() {\n\
524+ \ EffApply(PS__main())\n\
488525 \}\n\n\
489526 \"
490527
491528varDecl :: Text
492−varDecl = "const boxed"
493−
494−varRefDecl :: Text
495−varRefDecl = varDecl <> "&"
496−
497−renderArg' :: Text -> Text -> Text
498−renderArg' decl arg
499− | arg == unusedName = decl
500− | otherwise = decl <> " " <> arg
501−
502−renderArg :: Text -> Text
503−renderArg = renderArg' varRefDecl
529+varDecl = "var"
504530
505−renderArgByVal :: Text -> Text
506−renderArgByVal = renderArg' varDecl
531+renderArg :: Text -> Text -> Text
532+renderArg decl arg = arg <> " " <> decl
507533
508534foreignDict :: Text
509−foreignDict = "foreign"
535+foreignDict = "Foreign"
510536
511−staticValueBegin :: Text
512−staticValueBegin = "static const boxed _ = "
537+initName :: Text -> Text
538+initName s = "_" <> s <> "_init_"
513539
514−staticValueEnd :: Text
515−staticValueEnd = "return _;"
540+valueName :: Text -> Text
541+valueName s = "_" <> s <> "_value_"