git.iko.soy/rowtype-yoga/purescript-native
on 79aaba9 help sign in
52 files changed+2032−2726
since splitsnapshots
unifiedsplit
.gitignore−15 ChangeLog.md−3 LICENSE+16−26 PureScript.cabal+35 README-go.md−48 README.md+12−38 Setup.hs−2 Setup.lhs+6 app/Main.hs−250 default.nix−23 examples/Arrays.ps+16 examples/Assign.ps+7 examples/FFI.ps+5 examples/List.ps+24 examples/Maybe.ps+10 examples/Objects.ps+1 examples/Operators.ps+5 examples/Patterns.ps+5 package.yaml−86 psgo.cabal−145 src/CodeGen/IL.hs−321 src/CodeGen/IL/Common.hs−196 src/CodeGen/IL/Optimizer.hs−81 src/CodeGen/IL/Optimizer/Common.hs−18 src/CodeGen/IL/Optimizer/Inliner.hs−435 src/CodeGen/IL/Optimizer/MagicDo.hs−146 src/CodeGen/IL/Optimizer/TCO.hs−141 src/CodeGen/IL/Printer.hs−527 src/Main.hs+71 src/PureScript.hs+31 src/PureScript/CodeGen.hs+355 src/PureScript/Declarations.hs+33 src/PureScript/Kinds.hs+23 src/PureScript/Parser.hs+24 src/PureScript/Parser/Common.hs+73 src/PureScript/Parser/Declarations.hs+63 src/PureScript/Parser/Types.hs+80 src/PureScript/Parser/Values.hs+222 src/PureScript/TypeChecker.hs+80 src/PureScript/TypeChecker/Kinds.hs+160 src/PureScript/TypeChecker/Monad.hs+60 src/PureScript/TypeChecker/Types.hs+483 src/PureScript/Types.hs+40 src/PureScript/Values.hs+92 src/Tests.hs−141 stack.nix−23 stack.yaml−24 support/ffi-loader.go−30 support/go.mod.ffi-loader−2 support/go.mod.output−2 support/go.mod.working−1 test/Spec.hs−2
.gitignore−15
@@ -1,23 +1,8 @@
11dist
22cabal-dev
3−.cabal-sandbox
4−cabal.sandbox.config
53*.o
64*.hi
75*.chi
86*.chs.h
97*.lksh*
108.virthualenv
11−.psci_modules/
12−.test_modules/
13−bower_components/
14−node_modules
15−tmp/
16−.stack-work/
17−stack.yaml.lock
18−output
19−examples/docs/docs/
20−core-tests/full-core-docs.md
21−.psc-ide-port
22−.vscode/
23−result
ChangeLog.mddeleted−3
@@ -1,3 +0,0 @@
1−# Changelog for pscpp
2−
3−## Unreleased changes
LICENSE+16−26
@@ -1,30 +1,20 @@
1−Copyright Andy Arvanitis (c) 2018
1+The MIT License (MIT)
22
3−All rights reserved.
3+Copyright (c) 2013 Phil Freeman
44
5−Redistribution and use in source and binary forms, with or without
6−modification, are permitted provided that the following conditions are met:
5+Permission is hereby granted, free of charge, to any person obtaining a copy of
6+this software and associated documentation files (the "Software"), to deal in
7+the Software without restriction, including without limitation the rights to
8+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+the Software, and to permit persons to whom the Software is furnished to do so,
10+subject to the following conditions:
711
8− * Redistributions of source code must retain the above copyright
9− notice, this list of conditions and the following disclaimer.
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
1014
11− * Redistributions in binary form must reproduce the above
12− copyright notice, this list of conditions and the following
13− disclaimer in the documentation and/or other materials provided
14− with the distribution.
15−
16− * Neither the name of Author name here nor the names of other
17− contributors may be used to endorse or promote products derived
18− from this software without specific prior written permission.
19−
20−THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21−"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22−LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23−A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24−OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25−SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26−LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27−DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28−THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29−(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30−OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
PureScript.cabalnew file+35
@@ -0,0 +1,35 @@
1+name: Purescript
2+version: 0.0.1
3+cabal-version: >=1.2
4+build-type: Simple
5+license: MIT
6+license-file: LICENSE
7+copyright: (c) Phil Freeman 2013
8+maintainer: Phil Freeman <paf31@cantab.net>
9+stability: experimental
10+synopsis: PureScript Programming Language Compiler
11+description: A small compile-to-JS language with extensible records and type-safe blocks
12+author: Phil Freeman <paf31@cantab.net>
13+data-dir: ""
14+
15+library
16+ build-depends: base -any, cmdtheline -any, containers -any,
17+ mtl -any, parsec -any, utf8-string -any
18+ exposed-modules: PureScript
19+ exposed: True
20+ buildable: True
21+ hs-source-dirs: src
22+ other-modules: Main PureScript.CodeGen PureScript.Kinds
23+ PureScript.Parser PureScript.TypeChecker PureScript.Types
24+ PureScript.Values PureScript.Parser.Common
25+ PureScript.Parser.Declarations PureScript.Parser.Types
26+ PureScript.Parser.Values PureScript.TypeChecker.Kinds
27+ PureScript.TypeChecker.Monad PureScript.TypeChecker.Types
28+
29+executable psc
30+ build-depends: base -any, cmdtheline -any, containers -any,
31+ mtl -any, parsec -any, utf8-string -any
32+ main-is: Main.hs
33+ buildable: True
34+ hs-source-dirs: src
35+
README-go.mddeleted−48
@@ -1,48 +0,0 @@
1−
2−### psgo
3−
4−#### Performance
5−
6−* No runtime system beyond some support types and functions
7−* Uses PureScript's normal tail call optimization techniques for generated Go code
8−
9−#### Differences from PureScript:
10−
11−* Foreign imports/exports are Go instead of JavaScript – see [standard library foreign implementations](https://github.com/andyarvanitis/purescript-native-go-ffi)
12−* No Go-specific REPL
13−
14−#### Other notes:
15−
16−* The provided `Any` type is just an alias for `interface{}`
17−* PureScript types are represented in Go with:
18−
19− | PureScript | Go |
20− |------------|----|
21− |`Array` | `[]Any`|
22− |`String` | `string`|
23− |`Number` | `float64`|
24− |`Int` | `int`|
25− |`Char` | `string` (single UTF-8 entity)|
26− |`Boolean` | `bool`|
27− |Records | `map[string]Any`|
28−
29−#### Future ideas:
30−
31−* Nice facilities (modules) for concurrency/parallelism, using goroutines
32−
33−
34−#### Getting Started
35−This assumes you are running macOS (OS X) or a Unix-like system (Linux, *BSD, etc.).
36−
37−1. Choose a working directory wherever you like. Then create a `src` subdirectory under it, which will be where you will place your own PureScript source files.
38−
39−1. Initialize your project with `spago init`, and install any dependencies with `spago install` (please see their instructions if you haven't used it before).
40−
41−1. Add the `backend = "psgo"` option to your `spago.dhall` file. That way `spago` will use the psgo backend when compiling.
42−
43−1. You should now be ready to build a PureScript program:
44− * As stated above, place your source file(s) in the working directory's `src` subdirectory and execute `spago build`.
45−
46− * This will generate the Go source tree for your program and then build an executable binary. The resulting executable will be in your working directory and will be named `Main`. The generated source files will be under `output/`.
47−
48−---
README.md+12−38
@@ -1,41 +1,15 @@
1−[![PureScript](https://raw.githubusercontent.com/purescript/purescript/master/logo.png)](http://purescript.org)
1+purescript
2+==========
23
3−This is a platform-native compiler backend for [PureScript](https://github.com/purescript/purescript). It attempts to generate "sane", debuggable, and portable [C++11](https://isocpp.org/wiki/faq/cpp11) (or later) or [Go](https://golang.org/) code as an intermediate language, which is then compiled to a native executable binary. This also enables easy interoperability with existing C/C++ or Go frameworks and libraries on a number of platforms.
4+A small strongly, statically typed compile-to-JS language with basic extensible records and type-safe blocks
45
5−There are two utilities in the purescript-native "suite": `pscpp` and `psgo`. The source code in this branch is for `psgo`, the purescript-to-Go transpiler. For the source code of the `pscpp` purescript-to-C++ transpiler, please see the [cpp branch](https://github.com/andyarvanitis/purescript-native/tree/cpp).
6+## Current Features
67
7−#### Platforms
8−* Although purescript-native should work on any platform supporting PureScript and modern C++ or Go, the generated code and resulting binary executables have been tested on:
9− * macOS Mojave 10.14.5 – full test suite
10− * For C++, Xcode 10.2.1's `clang` was used
11− * For Go, `go` version 1.12.7 was used
12− * Windows 10 x64 – full test suite
13− * C++: Visual Studio 2017 and `clang`
14− * Go: `go` version 1.12.7
15− * Linux Debian 9.5 amd64 – full test suite (C++)
16− * Default versions of `clang` and `gcc`
17− * Linux Debian 10 amd64 – full test suite (Go)
18− * Default version of `go`
19− * Raspberry Pi 3 B+ Raspbian official build (ARM), default versions of `clang` and `gcc`
20−
21−
22−#### Requirements for building `pscpp` and `psgo`
23−
24−* [Haskell Stack](https://docs.haskellstack.org/en/stable/README/) (if you're running macOS 10.14.5+, you can use pre-built binaries from [here](https://github.com/andyarvanitis/purescript-native/releases/))
25−
26−#### Requirements for using PureScript + purescript-native
27−
28−* A recent version (0.13+) of [purescript](https://github.com/purescript/purescript/releases).
29−
30−* For `pscpp`, a C++11-capable toolchain, e.g. recent versions of clang, gcc, Microsoft Visual Studio
31− * GNU Make + `psc-package` is the default supported build tool, but you should be able to use your favorite package manager, C++ build system, tools, debuggers, etc.
32−* For `psgo`, the [Go toolchain](https://golang.org) for your system
33− * You can use your favorite PureScript package manager and build tools – but for simplicity, [`spago`](https://github.com/spacchetti/spago) is recommended.
34−
35−
36−#### For more information and a Getting Started guide, please see
37−* [`pscpp`](https://github.com/andyarvanitis/purescript-native/blob/cpp/README-cpp.md)
38−* [`psgo`](https://github.com/andyarvanitis/purescript-native/blob/golang/README-go.md)
39−
40−
41−---
8+- Full Type Inference
9+- Higher Kinded Polymorphism
10+- Support for basic Javascript types
11+- Extensible records
12+- Type-safe blocks with for/while/assignment etc.
13+- Functions with multiple arguments
14+- Pattern matching
15+- Simple FFI
Setup.hsdeleted−2
@@ -1,2 +0,0 @@
1−import Distribution.Simple
2−main = defaultMain
Setup.lhsnew file+6
@@ -0,0 +1,6 @@
1+#!/usr/bin/runhaskell
2+> module Main where
3+> import Distribution.Simple
4+> main :: IO ()
5+> main = defaultMain
6+
app/Main.hsdeleted−250
@@ -1,250 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−{-# LANGUAGE RankNTypes #-}
3−{-# LANGUAGE TemplateHaskell #-}
4−
5−module Main where
6−
7−import Control.Monad (when)
8−import qualified Control.Monad.Parallel as Par
9−import Data.Aeson
10−import Data.Aeson.Types
11−import Data.Char
12−import Data.FileEmbed (embedFile)
13−import Data.List (delete, intercalate, isPrefixOf, nub, partition, (\\))
14−import Data.Maybe
15−import Data.Monoid ((<>))
16−import Data.Version
17−import Control.Monad.Supply
18−import Control.Monad.Supply.Class
19−import Text.Printf
20−
21−import System.Environment
22−import System.Directory (createDirectoryIfMissing, doesDirectoryExist, doesFileExist, getCurrentDirectory, getModificationTime)
23−import System.FilePath ((</>), joinPath, splitDirectories, takeDirectory)
24−import System.FilePath.Find
25−import System.Process
26−
27−import Data.Text (Text)
28−import qualified Data.Text as T
29−import qualified Data.Text.Encoding as T
30−import qualified Data.Text.Lazy as L
31−import qualified Data.Text.Lazy.Encoding as L
32−import qualified Data.ByteString as B
33−
34−import Development.GitRev
35−
36−import Language.PureScript.AST.Literals
37−import Language.PureScript.CoreFn
38−import Language.PureScript.CoreFn.FromJSON
39−
40−import CodeGen.IL
41−import CodeGen.IL.Common
42−import CodeGen.IL.Printer
43−
44−import Tests
45−
46−data Command = Build | Run (Maybe String)
47−
48−parseJson :: Text -> Value
49−parseJson text
50− | Just fileJson <- decode . L.encodeUtf8 $ L.fromStrict text = fileJson
51− | otherwise = error "Bad json"
52−
53−jsonToModule :: Value -> Module Ann
54−jsonToModule value =
55− case parse moduleFromJSON value of
56− Success (_, r) -> r
57− _ -> error "Failed parsing corefn. Psgo currently supports purescript <= 0.13.8"
58−
59−splitArgs :: [String] -> ([String], Maybe String, [String])
60−splitArgs args =
61− let (opts, files) = partition (isPrefixOf "--") args
62− opts' = (map . map) toLower opts
63− (moduleName, files') =
64− if null files
65− then (Nothing, files)
66− else
67− if "--run" `elem` opts' && length (files) >= 1
68− then do
69− let file0 = head files
70− files' = tail files
71− case file0 of
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')
77−
78−main :: IO ()
79−main = do
80− args <- getArgs
81− -- let (opts, files) = partition (isPrefixOf "--") args
82− let (opts, moduleName, files) = splitArgs args
83− opts' = (map . map) toLower opts
84− if "--tests" `elem` opts'
85− then runTests
86− else do
87− if "--help" `elem` opts' || "--version" `elem` opts'
88− then do
89− when ("--help" `elem` opts') $ do
90− putStrLn help
91− when ("--version" `elem` opts') $ do
92− let branch = $(gitBranch)
93− details | branch == "golang" = "master, commit " ++ $(gitHash)
94− | otherwise = branch
95− putStrLn $ details ++ if $(gitDirty) then " (DIRTY)" else ""
96− else do
97− if null files
98− then do
99− currentDir <- getCurrentDirectory
100− processFiles opts' [currentDir]
101− else
102− processFiles opts' files
103− if "--run" `elem` opts
104− then runBuildTool $ Run moduleName
105− else when ("--no-build" `notElem` opts) $
106− runBuildTool Build
107− return ()
108− where
109− processFiles :: [String] -> [FilePath] -> IO ()
110− processFiles opts [file] = do
111− isDir <- doesDirectoryExist file
112− if isDir then do
113− files <- find always (fileName ==? corefn) file
114− if null files
115− then errorNoCorefnFiles
116− else generateFiles opts files
117− else generateFiles opts [file]
118− processFiles opts files = do
119− generateFiles opts files
120− basePath :: [FilePath] -> FilePath
121− basePath files =
122− let filepath = takeDirectory (head files) in
123− joinPath $ (init $ splitDirectories filepath)
124− generateFiles :: [String] -> [FilePath] -> IO ()
125− generateFiles opts files = do
126− let baseOutpath = basePath files
127− writeSupportFiles baseOutpath
128− Par.mapM (generateCode opts baseOutpath) files
129− return ()
130− runBuildTool :: Command -> IO ()
131− runBuildTool cmd = do
132− project <- projectEnv
133− case cmd of
134− Build -> do
135− callProcess "go" ["build", T.unpack project </> modPrefix' </> "Main"]
136− Run moduleName -> do
137− callProcess "go" ["run", T.unpack project </> modPrefix' </> fromMaybe "Main" moduleName]
138− return ()
139−
140−generateCode :: [String] -> FilePath -> FilePath -> IO ()
141−generateCode opts baseOutpath jsonFile = do
142− jsonModTime <- getModificationTime jsonFile
143− let filepath = takeDirectory jsonFile
144− dirparts = splitDirectories $ filepath
145− mname = last dirparts
146− basedir = joinPath $ init dirparts
147− mname' = T.pack mname
148− possibleFileName = basedir </> (T.unpack mname') </> implFileName mname'
149− exists <- doesFileExist possibleFileName
150− if exists
151− then do
152− modTime <- getModificationTime possibleFileName
153− when (modTime < jsonModTime) $
154− transpile opts baseOutpath jsonFile
155− else transpile opts baseOutpath jsonFile
156−
157−transpile :: [String] -> FilePath -> FilePath -> IO ()
158−transpile opts baseOutpath jsonFile = do
159− jsonText <- T.decodeUtf8 <$> B.readFile jsonFile
160− project <- projectEnv
161− let module' = jsonToModule $ parseJson jsonText
162− ((_, foreigns, asts, implHeader, implFooter), _) <- runSupplyT 5 (moduleToIL module' project)
163− let mn = moduleNameToIL' $ moduleName module'
164− implementation = prettyPrintIL asts
165− outpath = joinPath [baseOutpath, T.unpack mn]
166− implPath = outpath </> implFileName mn
167− createDirectoryIfMissing True outpath
168− putStrLn implPath
169− B.writeFile implPath $ T.encodeUtf8 (implHeader <> implementation <> implFooter)
170−
171−writeSupportFiles :: FilePath -> IO ()
172−writeSupportFiles baseOutpath = do
173− currentDir <- getCurrentDirectory
174− let outputdir = T.pack $ baseOutpath \\ currentDir
175− ffiOutpath = currentDir </> subdir
176− createDirectoryIfMissing True baseOutpath
177− createDirectoryIfMissing True ffiOutpath
178− writeModuleFile outputdir currentDir $(embedFile "support/go.mod.working")
179− writeModuleFile outputdir baseOutpath $(embedFile "support/go.mod.output")
180− writeModuleFile outputdir ffiOutpath $(embedFile "support/go.mod.ffi-loader")
181− writeLoaderFile ffiOutpath $(embedFile "support/ffi-loader.go")
182− where
183− writeModuleFile :: Text -> FilePath -> B.ByteString -> IO ()
184− writeModuleFile outputdir path modText = do
185− let goModSource = path </> "go.mod"
186− goModSourceExists <- doesFileExist goModSource
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'
194− B.writeFile goModSource $ T.encodeUtf8 modText'
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"
201− loaderSourceExists <- doesFileExist loaderSource
202− when (not loaderSourceExists) $ do
203− B.writeFile loaderSource loaderText
204−
205−implFileName :: Text -> FilePath
206−implFileName mn = ((\c -> if c == '.' then '_' else c) <$> T.unpack mn) <> ".go"
207−
208−projectEnv :: IO Text
209−projectEnv = do
210− T.pack . fromMaybe defaultProject <$> lookupEnv goproject
211−
212−help :: String
213−help = "Usage: psgo OPTIONS COREFN-FILES\n\
214− \ PureScript to native (via go) compiler\n\n\
215− \Available options:\n\
216− \ --help Show this help text\n\n\
217− \ --version Show the version number\n\n\
218− \ --run Run the generated go code directly, without building an\n\
219− \ executable\n\
220− \ --no-build Generate go source files, but do not build an executable\n\
221− \ --tests Run test cases (under construction)\n\n\
222− \See also:\n\
223− \ purs compile --help\n"
224−
225−corefn :: String
226−corefn = "corefn.json"
227−
228−goSrc :: String
229−goSrc = ".go"
230−
231−goproject :: String
232−goproject = "GOPROJECT"
233−
234−defaultProject :: String
235−defaultProject = "project.localhost"
236−
237−modPrefix' :: String
238−modPrefix' = T.unpack modPrefix
239−
240−ffiLoader' :: String
241−ffiLoader' = T.unpack ffiLoader
242−
243−subdir :: String
244−subdir = T.unpack modLabel
245−
246−errorNoCorefnFiles :: IO ()
247−errorNoCorefnFiles = do
248− ioError . userError $ "no compiled purescript '" <> corefn <> "' files found –\n" <>
249− " make sure to use the '--codegen corefn' option with your purs\n" <>
250− " project build tool"
default.nixdeleted−23
@@ -1,23 +0,0 @@
1−let
2− haskellNix = import (builtins.fetchTarball https://github.com/input-output-hk/haskell.nix/archive/master.tar.gz) {};
3− nixpkgsSrc = haskellNix.sources.nixpkgs-1903; # has hsc2hs-0.68.4
4−
5− hsc2hsOverlay = self: super: {
6− buildPackages = super.buildPackages // {
7− hsc2hs = super.haskellPackages.hsc2hs;
8− };
9− };
10−
11− nixpkgsArgs = haskellNix.nixpkgsArgs // {
12− overlays = haskellNix.nixpkgsArgs.overlays ++ [ hsc2hsOverlay ];
13− };
14−in
15−{ pkgs ? import nixpkgsSrc nixpkgsArgs
16−}:
17−
18−pkgs.haskell-nix.stackProject {
19− src = pkgs.haskell-nix.haskellLib.cleanGit {
20− name = "purescript-native";
21− src = ./.;
22− };
23−}
examples/Arrays.psnew file+16
@@ -0,0 +1,16 @@
1+test1 = \arr -> arr[0] + arr[1]
2+
3+test2 = \arr -> case arr of
4+ { [x, y] -> x + y
5+ ; [x] -> x
6+ ; [] -> 0
7+ ; [x, y : _] -> x + y
8+ }
9+
10+data Tree = One Number | Some [Tree]
11+
12+test3 = \tree, sum -> case tree of
13+ { One n -> n
14+ ; Some [n1, n2 : rest] -> test3(n1, sum) * 10 + test3(n2, sum) * 5 + sum(rest)
15+ }
16+
examples/Assign.psnew file+7
@@ -0,0 +1,7 @@
1+test = \ -> {
2+ var x = [];
3+ for (var i = 0; i < 10; i = i + 1) {
4+ x[i] = i;
5+ }
6+ return x;
7+}
examples/FFI.psnew file+5
@@ -0,0 +1,5 @@
1+extern foo :: (String) -> String
2+
3+bar :: (String) -> String
4+
5+bar = \x -> foo(x ++ "bar")
examples/List.psnew file+24
@@ -0,0 +1,24 @@
1+data List a
2+ = Nil
3+ | Cons
4+ { head :: a
5+ ; tail :: List a
6+ }
7+
8+null = \l -> case l of
9+ { Nil -> true
10+ ; _ -> false
11+ }
12+
13+concat = \l1 -> \l2 -> case l1 of
14+ { Nil -> l2
15+ ; Cons x -> Cons(
16+ { head: x.head
17+ , tail: concat(x.tail)(l2)
18+ })
19+ }
20+
21+flatten = \xss -> case xss of
22+ { Nil -> Nil
23+ ; Cons cons -> concat(cons.head)(flatten(cons.tail))
24+ }
examples/Maybe.psnew file+10
@@ -0,0 +1,10 @@
1+data Maybe a = Nothing | Just a
2+
3+maybe = \b -> \f -> \m -> case m of
4+ { Nothing -> b
5+ ; Just a -> f(a)
6+ }
7+
8+fmap = \m -> \f -> maybe(Nothing)(\a -> Just(f(a)))(m)
9+
10+bind = \m -> \f -> maybe(Nothing)(f)(m)
examples/Objects.psnew file+1
@@ -0,0 +1 @@
1+test = \x -> x.foo + x.bar
examples/Operators.psnew file+5
@@ -0,0 +1,5 @@
1+test1 = \x, y, z -> x * y + z(x)(y)
2+
3+test2 = (\x -> (x.foo)(false))({ foo : \_ -> 1 })
4+
5+test3 = (\x, y -> x)(1 + 2 * (1 + 2), true && (false || false))
examples/Patterns.psnew file+5
@@ -0,0 +1,5 @@
1+test = \x -> case x of
2+ { { str = "Foo", bool = true } -> true
3+ ; { str = "Bar", bool = b } -> b
4+ ; _ -> false
5+ }
package.yamldeleted−86
@@ -1,86 +0,0 @@
1−name: psgo
2−version: 0.1.0.0
3−github: "andyarvanitis/purescript-native"
4−license: BSD3
5−author: "Andy Arvanitis"
6−maintainer: "example@example.com"
7−copyright: "2018 Andy Arvanitis"
8−
9−extra-source-files:
10−- README.md
11−- ChangeLog.md
12−- stack.yaml
13−- support/*
14−
15−# Metadata used when publishing your package
16−# synopsis: Short description of your package
17−# category: Web
18−
19−# To avoid duplicated efforts in documentation and dealing with the
20−# complications of embedding Haddock markup inside cabal files, it is
21−# common to point users to the README.md file.
22−description: Please see the README on Github at <https://github.com/andyarvanitis/purescript-native#readme>
23−
24−dependencies:
25−- base >= 4.7 && < 5
26−- bytestring >= 0.10.8.2 && < 0.11
27−- purescript
28−- base-compat >=0.6.0
29−- protolude >=0.1.6
30−- text
31−- containers
32−- filepath
33−- monad-parallel >= 0.7.2.2 && <0.8
34−- pattern-arrows >=0.0.2 && <0.1
35−- safe >=0.3.9 && <0.4
36−- transformers >=0.3.0 && <0.6
37−- mtl >=2.1.0 && <2.3.0
38−- aeson >=1.0 && <1.5
39−- directory
40−- process
41−- file-embed
42−- filemanip
43−- gitrev
44−
45−library:
46− source-dirs: src
47− default-extensions:
48− - ConstraintKinds
49− - DataKinds
50− - DeriveFunctor
51− - EmptyDataDecls
52− - FlexibleContexts
53− - KindSignatures
54− - LambdaCase
55− - MultiParamTypeClasses
56− - NoImplicitPrelude
57− - PatternGuards
58− - PatternSynonyms
59− - RankNTypes
60− - RecordWildCards
61− - OverloadedStrings
62− - ScopedTypeVariables
63− - TupleSections
64− - ViewPatterns
65−
66−executables:
67− psgo:
68− main: Main.hs
69− source-dirs: app
70− ghc-options:
71− - -threaded
72− - -rtsopts
73− - -with-rtsopts=-N
74− dependencies:
75− - psgo
76−
77−tests:
78− psgo-test:
79− main: Spec.hs
80− source-dirs: test
81− ghc-options:
82− - -threaded
83− - -rtsopts
84− - -with-rtsopts=-N
85− dependencies:
86− - psgo
psgo.cabaldeleted−145
@@ -1,145 +0,0 @@
1−cabal-version: 1.12
2−
3−-- This file has been generated from package.yaml by hpack version 0.35.0.
4−--
5−-- see: https://github.com/sol/hpack
6−
7−name: psgo
8−version: 0.1.0.0
9−description: Please see the README on Github at <https://github.com/andyarvanitis/purescript-native#readme>
10−homepage: https://github.com/andyarvanitis/purescript-native#readme
11−bug-reports: https://github.com/andyarvanitis/purescript-native/issues
12−author: Andy Arvanitis
13−maintainer: example@example.com
14−copyright: 2018 Andy Arvanitis
15−license: BSD3
16−license-file: LICENSE
17−build-type: Simple
18−extra-source-files:
19− README.md
20− ChangeLog.md
21− stack.yaml
22− support/ffi-loader.go
23− support/go.mod.ffi-loader
24− support/go.mod.output
25− support/go.mod.working
26−
27−source-repository head
28− type: git
29− location: https://github.com/andyarvanitis/purescript-native
30−
31−library
32− exposed-modules:
33− CodeGen.IL
34− CodeGen.IL.Common
35− CodeGen.IL.Optimizer
36− CodeGen.IL.Optimizer.Common
37− CodeGen.IL.Optimizer.Inliner
38− CodeGen.IL.Optimizer.MagicDo
39− CodeGen.IL.Optimizer.TCO
40− CodeGen.IL.Printer
41− Tests
42− other-modules:
43− Paths_psgo
44− hs-source-dirs:
45− src
46− default-extensions:
47− ConstraintKinds
48− DataKinds
49− DeriveFunctor
50− EmptyDataDecls
51− FlexibleContexts
52− KindSignatures
53− LambdaCase
54− MultiParamTypeClasses
55− NoImplicitPrelude
56− PatternGuards
57− PatternSynonyms
58− RankNTypes
59− RecordWildCards
60− OverloadedStrings
61− ScopedTypeVariables
62− TupleSections
63− ViewPatterns
64− build-depends:
65− aeson >=1.0 && <1.5
66− , base >=4.7 && <5
67− , base-compat >=0.6.0
68− , bytestring >=0.10.8.2 && <0.11
69− , containers
70− , directory
71− , file-embed
72− , filemanip
73− , filepath
74− , gitrev
75− , monad-parallel >=0.7.2.2 && <0.8
76− , mtl >=2.1.0 && <2.3.0
77− , pattern-arrows >=0.0.2 && <0.1
78− , process
79− , protolude >=0.1.6
80− , purescript
81− , safe >=0.3.9 && <0.4
82− , text
83− , transformers >=0.3.0 && <0.6
84− default-language: Haskell2010
85−
86−executable psgo
87− main-is: Main.hs
88− other-modules:
89− Paths_psgo
90− hs-source-dirs:
91− app
92− ghc-options: -threaded -rtsopts -with-rtsopts=-N
93− build-depends:
94− aeson >=1.0 && <1.5
95− , base >=4.7 && <5
96− , base-compat >=0.6.0
97− , bytestring >=0.10.8.2 && <0.11
98− , containers
99− , directory
100− , file-embed
101− , filemanip
102− , filepath
103− , gitrev
104− , monad-parallel >=0.7.2.2 && <0.8
105− , mtl >=2.1.0 && <2.3.0
106− , pattern-arrows >=0.0.2 && <0.1
107− , process
108− , protolude >=0.1.6
109− , psgo
110− , purescript
111− , safe >=0.3.9 && <0.4
112− , text
113− , transformers >=0.3.0 && <0.6
114− default-language: Haskell2010
115−
116−test-suite psgo-test
117− type: exitcode-stdio-1.0
118− main-is: Spec.hs
119− other-modules:
120− Paths_psgo
121− hs-source-dirs:
122− test
123− ghc-options: -threaded -rtsopts -with-rtsopts=-N
124− build-depends:
125− aeson >=1.0 && <1.5
126− , base >=4.7 && <5
127− , base-compat >=0.6.0
128− , bytestring >=0.10.8.2 && <0.11
129− , containers
130− , directory
131− , file-embed
132− , filemanip
133− , filepath
134− , gitrev
135− , monad-parallel >=0.7.2.2 && <0.8
136− , mtl >=2.1.0 && <2.3.0
137− , pattern-arrows >=0.0.2 && <0.1
138− , process
139− , protolude >=0.1.6
140− , psgo
141− , purescript
142− , safe >=0.3.9 && <0.4
143− , text
144− , transformers >=0.3.0 && <0.6
145− default-language: Haskell2010
src/CodeGen/IL.hsdeleted−321
@@ -1,321 +0,0 @@
1−-- | This module generates code in the core imperative representation from
2−-- elaborated PureScript code.
3−module CodeGen.IL
4− ( module AST
5− , module Common
6− , moduleToIL
7− ) where
8−
9−import Prelude.Compat
10−import Protolude (ordNub)
11−
12−import Control.Arrow ((&&&))
13−import Control.Monad (forM, liftM, replicateM, void)
14−import Control.Monad.Supply.Class
15−
16−import Data.List ((\\), delete, intersect, nub)
17−import qualified Data.Foldable as F
18−import qualified Data.Map as M
19−import Data.Maybe (fromMaybe, isNothing, mapMaybe)
20−import Data.Monoid ((<>))
21−import Data.String (fromString)
22−import Data.Text (Text)
23−import qualified Data.Text as T
24−
25−import Language.PureScript.AST.SourcePos
26−import Language.PureScript.CoreImp.AST (AST)
27−import qualified Language.PureScript.CoreImp.AST as AST
28−import Language.PureScript.CoreFn
29−import Language.PureScript.Crash
30−import Language.PureScript.Names
31−import Language.PureScript.Options
32−import Language.PureScript.PSString (PSString, mkString)
33−import Language.PureScript.Traversals (sndM)
34−import qualified Language.PureScript.Constants as C
35−
36−import System.FilePath.Posix ((</>))
37−
38−import CodeGen.IL.Common as Common
39−import CodeGen.IL.Optimizer
40−import CodeGen.IL.Printer
41−
42−data DeclType = ModuleDecl | LetDecl | RecLetDecl deriving (Eq)
43−
44−-- | Generate code in the simplified intermediate representation for all declarations in a
45−-- module.
46−moduleToIL
47− :: forall m
48− -- . (Monad m, MonadReader Options m, MonadSupply m, MonadError MultipleErrors m)
49− . (Monad m, MonadSupply m)
50− => Module Ann
51− -> Text
52− -> m (Text, [Text], [AST], Text, Text)
53−moduleToIL (Module _ coms mn _ imps _ foreigns decls) project =
54− do
55− ilDecls <- mapM (bindToIL ModuleDecl) decls
56− optimized <- traverse (traverse (optimize modName')) ilDecls
57− let optimized' = concat optimized
58− values = annotValue <$> optimized'
59− foreigns' = moduleIdentToIL <$> foreigns
60− interface = interfaceSource modName values foreigns
61− imports = nub . concat $ importToIL <$> optimized'
62− implHeader = implHeaderSource modName imports project
63− implFooter = implFooterSource (runModuleName mn) foreigns
64− return $ (interface, foreigns', optimized', implHeader, implFooter)
65− where
66− modName = moduleNameToIL mn
67− modName' = AST.Var Nothing modName
68−
69− annotValue :: AST -> (Text, Bool)
70− annotValue (AST.Function _ (Just name) [] (AST.Block _ [AST.Return _ ret]))
71− | isLiteral ret = (name, True)
72− annotValue (AST.Function _ (Just name) [] _) = (name, False)
73− annotValue _ = error "Unexpected top-level value form"
74−
75− -- | Extracts all declaration names from a binding group.
76− getNames :: Bind Ann -> [Ident]
77− getNames (NonRec _ ident _) = [ident]
78− getNames (Rec vals) = map (snd . fst) vals
79−
80− -- | Generates IL code for a module import
81− --
82− importToIL :: AST -> [Text]
83− importToIL = AST.everything (++) modRef
84− where
85− modRef (AST.Indexer _ (AST.Var _ _) (AST.Var _ mname))
86− | not $ T.null mname = [extract mname]
87− modRef _ = []
88− extract :: Text -> Text
89− extract = T.replace "_" "." . T.dropWhileEnd (=='_')
90−
91− -- |
92− -- Generate code in the simplified intermediate representation for a declaration
93− --
94− bindToIL :: DeclType -> Bind Ann -> m [AST]
95− bindToIL dt (NonRec ann ident val) = return <$> nonRecToIL dt ann ident val
96− bindToIL dt (Rec vals) = forM vals (uncurry . uncurry $ nonRecToIL dt')
97− where
98− dt' = if dt == LetDecl then RecLetDecl else dt
99−
100− -- | Generate code in the simplified intermediate representation for a single non-recursive
101− -- declaration.
102− --
103− -- The main purpose of this function is to handle code generation for comments.
104− nonRecToIL :: DeclType -> Ann -> Ident -> Expr Ann -> m AST
105− nonRecToIL dt a i e@(extractAnn -> (_, com, _, _)) | not (null com) = do
106− -- withoutComment <- asks optionsNoComments
107− let withoutComment = False
108− if withoutComment
109− then nonRecToIL dt a i (modifyAnn removeComments e)
110− else AST.Comment Nothing com <$> nonRecToIL dt a i (modifyAnn removeComments e)
111− nonRecToIL ModuleDecl (ss, _, _, _) ident val = do
112− il <- valueToIL val
113− pure $ AST.Function Nothing (Just $ moduleIdentToIL ident) [] (AST.Block Nothing [AST.Return Nothing il])
114− nonRecToIL RecLetDecl (ss, _, _, _) ident val = do
115− ilExpr <- valueToIL val
116− pure $ AST.Assignment Nothing (AST.Var Nothing $ identToIL ident) ilExpr
117− nonRecToIL _ (ss, _, _, _) ident val = do
118− il <- valueToIL val
119− pure $ AST.VariableIntroduction Nothing (identToIL ident) (Just il)
120−
121− -- | Generate code in the simplified intermediate representation for a variable based on a
122− -- PureScript identifier.
123− var :: Ident -> AST
124− var = AST.Var Nothing . identToIL
125−
126− accessorString :: PSString -> AST -> AST
127− accessorString prop = AST.Indexer Nothing (AST.StringLiteral Nothing prop)
128−
129− -- | Generate code in the simplified intermediate representation for a value or expression.
130−
131− valueToIL :: Expr Ann -> m AST
132− valueToIL (Literal (pos, _, _, _) l) = literalToValueIL pos l
133− valueToIL (Accessor _ prop val) =
134− accessorString prop <$> valueToIL val
135− valueToIL (ObjectUpdate _ o ps) = do
136− obj <- valueToIL o
137− updates <- mapM (sndM valueToIL) ps
138− obj' <- freshName'
139− let objVar = AST.Var Nothing obj'
140− copy = AST.VariableIntroduction Nothing obj' (Just $ copyDict obj)
141− assign (k, v) = AST.Assignment Nothing (accessorString k objVar) v
142− sts = copy : (assign <$> updates) ++ [AST.Return Nothing objVar]
143− return $ AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing sts)) []
144− valueToIL (Abs _ arg val) = do
145− ret <- valueToIL val
146− let ilArg = case arg of
147− UnusedIdent -> []
148− _ -> [identToIL arg]
149− return $ AST.Function Nothing Nothing ilArg (AST.Block Nothing [AST.Return Nothing ret])
150− valueToIL e@App{} = do
151− let (f, args) = unApp e []
152− args' <- mapM valueToIL args
153− fn <- valueToIL f
154− case f of
155− Var (_, _, _, Just IsNewtype) _ -> return (head args')
156− _ -> flip (foldl (\fn a -> AST.App Nothing fn [a])) args' <$> valueToIL f
157− where
158− unApp :: Expr Ann -> [Expr Ann] -> (Expr Ann, [Expr Ann])
159− unApp (App _ val arg) args = unApp val (arg : args)
160− unApp other args = (other, args)
161− valueToIL (Var _ ident) = return $ varToIL ident
162− valueToIL (Case (ss, _, _, _) values binders) = do
163− vals <- mapM valueToIL values
164− bindersToIL ss binders vals
165− valueToIL (Let _ ds val) = do
166− let recurs = concatMap getNames $ filter isRec ds
167− recurDs = (\v -> AST.VariableIntroduction Nothing (identToIL v) Nothing) <$> recurs
168− ds' <- concat <$> mapM (bindToIL LetDecl) ds
169− ret <- valueToIL val
170− return $ AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing (recurDs ++ ds' ++ [AST.Return Nothing ret]))) []
171− where
172− isRec :: Bind Ann -> Bool
173− isRec (Rec _) = True
174− isRec _ = False
175− valueToIL (Constructor (_, _, _, Just IsNewtype) _ (ProperName ctor) _) = error "IsNewtype"
176− valueToIL (Constructor _ _ (ProperName ctor) fields) =
177− let body = AST.ObjectLiteral Nothing $ (mkString ctor, AST.BooleanLiteral Nothing True) :
178− ((\field -> (mkString (identToIL field), var field)) `map` fields)
179− fn = foldr (\f inner -> AST.Function Nothing Nothing [identToIL f] (AST.Block Nothing [AST.Return Nothing inner])) body fields
180− in return fn
181−
182−
183− iife :: Text -> [AST] -> AST
184− iife v exprs = AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing $ exprs ++ [AST.Return Nothing $ AST.Var Nothing v])) []
185−
186− literalToValueIL :: SourceSpan -> Literal (Expr Ann) -> m AST
187− literalToValueIL ss (NumericLiteral (Left i)) = return $ AST.NumericLiteral (Just ss) (Left i)
188− literalToValueIL ss (NumericLiteral (Right n)) = return $ AST.NumericLiteral (Just ss) (Right n)
189− literalToValueIL ss (StringLiteral s) = return $ AST.StringLiteral (Just ss) s
190− literalToValueIL ss (CharLiteral c) = return $ AST.StringLiteral (Just ss) (fromString [c])
191− literalToValueIL ss (BooleanLiteral b) = return $ AST.BooleanLiteral (Just ss) b
192− literalToValueIL ss (ArrayLiteral xs) = AST.ArrayLiteral (Just ss) <$> mapM valueToIL xs
193− literalToValueIL ss (ObjectLiteral ps) = AST.ObjectLiteral (Just ss) <$> mapM (sndM valueToIL) ps
194−
195− -- | Generate code in the simplified intermediate representation for a reference to a
196− -- variable.
197− varToIL :: Qualified Ident -> AST
198− varToIL (Qualified Nothing ident) = var ident
199− varToIL qual = qualifiedToIL id qual
200−
201− -- | Generate code in the simplified intermediate representation for a reference to a
202− -- variable that may have a qualified name.
203− qualifiedToIL :: (a -> Ident) -> Qualified a -> AST
204− qualifiedToIL f (Qualified (Just (ModuleName mn')) a) | mn' == C.prim = AST.Var Nothing . moduleIdentToIL $ f a
205− qualifiedToIL f (Qualified (Just mn') a) | mn /= mn' = AST.Indexer Nothing (AST.Var Nothing . moduleIdentToIL $ f a) (AST.Var Nothing (moduleNameToIL mn'))
206− qualifiedToIL f (Qualified _ a) = AST.Indexer Nothing (AST.Var Nothing . moduleIdentToIL $ f a) (AST.Var Nothing "")
207−
208− -- foreignIdent :: Ident -> AST
209− -- foreignIdent ident = accessorString (mkString $ runIdent ident) (AST.Var Nothing "$foreign")
210−
211− -- | Generate code in the simplified intermediate representation for pattern match binders
212− -- and guards.
213− bindersToIL :: SourceSpan -> [CaseAlternative Ann] -> [AST] -> m AST
214− bindersToIL ss binders vals = do
215− valNames <- replicateM (length vals) freshName'
216− let assignments = zipWith (AST.VariableIntroduction Nothing) valNames (map Just vals)
217− ils <- forM binders $ \(CaseAlternative bs result) -> do
218− ret <- guardsToIL result
219− go valNames ret bs
220− return $ AST.App Nothing (AST.Function Nothing Nothing [] (AST.Block Nothing (assignments ++ concat ils ++ [AST.Throw Nothing (AST.StringLiteral Nothing $ mkString failedPatternMessage)])))
221− []
222− where
223− go :: [Text] -> [AST] -> [Binder Ann] -> m [AST]
224− go _ done [] = return done
225− go (v:vs) done' (b:bs) = do
226− done'' <- go vs done' bs
227− binderToIL v done'' b
228− go _ _ _ = internalError "Invalid arguments to bindersToIL"
229−
230− failedPatternMessage :: Text
231− failedPatternMessage = "Failed pattern match at " <> runModuleName mn <> " " <> displayStartEndPos ss
232−
233− guardsToIL :: Either [(Guard Ann, Expr Ann)] (Expr Ann) -> m [AST]
234− guardsToIL (Left gs) = traverse genGuard gs where
235− genGuard (cond, val) = do
236− cond' <- valueToIL cond
237− val' <- valueToIL val
238− return
239− (AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo cond' (AST.BooleanLiteral Nothing True))
240− (AST.Block Nothing [AST.Return Nothing val']) Nothing)
241−
242− guardsToIL (Right v) = return . AST.Return Nothing <$> valueToIL v
243−
244− -- | Generate code in the simplified intermediate representation for a pattern match
245− -- binder.
246− binderToIL :: Text -> [AST] -> Binder Ann -> m [AST]
247− binderToIL _ done NullBinder{} = return done
248− binderToIL varName done (LiteralBinder _ l) =
249− literalToBinderIL varName done l
250− binderToIL varName done (VarBinder _ ident) =
251− return (AST.VariableIntroduction Nothing (identToIL ident) (Just (AST.Var Nothing varName)) : done)
252− binderToIL varName done (ConstructorBinder (_, _, _, Just IsNewtype) _ _ [b]) =
253− binderToIL varName done b
254− binderToIL varName done (ConstructorBinder (_, _, _, Just (IsConstructor ctorType fields)) _ (Qualified _ (ProperName ctor)) bs) = do
255− il <- go (zip fields bs) done
256− return $ case ctorType of
257− ProductType -> il
258− SumType ->
259− [AST.IfElse Nothing (AST.InstanceOf Nothing (AST.Var Nothing varName) (AST.StringLiteral Nothing (mkString ctor)))
260− (AST.Block Nothing il)
261− Nothing]
262− where
263− go :: [(Ident, Binder Ann)] -> [AST] -> m [AST]
264− go [] done' = return done'
265− go ((field, binder) : remain) done' = do
266− argVar <- freshName'
267− done'' <- go remain done'
268− il <- binderToIL argVar done'' binder
269− return (AST.VariableIntroduction Nothing argVar (Just $ accessorString (mkString $ identToIL field) $ AST.Var Nothing varName) : il)
270−
271− binderToIL _ _ ConstructorBinder{} =
272− internalError "binderToIL: Invalid ConstructorBinder in binderToIL"
273− binderToIL varName done (NamedBinder _ ident binder) = do
274− il <- binderToIL varName done binder
275− return (AST.VariableIntroduction Nothing (identToIL ident) (Just (AST.Var Nothing varName)) : il)
276−
277− literalToBinderIL :: Text -> [AST] -> Literal (Binder Ann) -> m [AST]
278− literalToBinderIL varName done (NumericLiteral num) =
279− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.NumericLiteral Nothing num)) (AST.Block Nothing done) Nothing]
280− literalToBinderIL varName done (CharLiteral c) =
281− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.StringLiteral Nothing (fromString [c]))) (AST.Block Nothing done) Nothing]
282− literalToBinderIL varName done (StringLiteral str) =
283− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.StringLiteral Nothing str)) (AST.Block Nothing done) Nothing]
284− literalToBinderIL varName done (BooleanLiteral True) =
285− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.BooleanLiteral Nothing True)) (AST.Block Nothing done) Nothing]
286− literalToBinderIL varName done (BooleanLiteral False) =
287− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo (AST.Var Nothing varName) (AST.BooleanLiteral Nothing False)) (AST.Block Nothing done) Nothing]
288− -- return [AST.IfElse Nothing (AST.Unary Nothing AST.Not (AST.Var Nothing varName)) (AST.Block Nothing done) Nothing]
289− literalToBinderIL varName done (ObjectLiteral bs) = go done bs
290− where
291− go :: [AST] -> [(PSString, Binder Ann)] -> m [AST]
292− go done' [] = return done'
293− go done' ((prop, binder):bs') = do
294− propVar <- freshName'
295− done'' <- go done' bs'
296− il <- binderToIL propVar done'' binder
297− return (AST.VariableIntroduction Nothing propVar (Just (accessorString prop (AST.Var Nothing varName))) : il)
298− literalToBinderIL varName done (ArrayLiteral bs) = do
299− il <- go done 0 bs
300− return [AST.IfElse Nothing (AST.Binary Nothing AST.EqualTo
301− (arrayLength $ AST.Var Nothing varName)
302− (AST.NumericLiteral Nothing (Left (fromIntegral $ length bs))))
303− (AST.Block Nothing il) Nothing]
304− where
305− go :: [AST] -> Integer -> [Binder Ann] -> m [AST]
306− go done' _ [] = return done'
307− go done' index (binder:bs') = do
308− elVar <- freshName'
309− done'' <- go done' (index + 1) bs'
310− il <- binderToIL elVar done'' binder
311− return (AST.VariableIntroduction Nothing elVar (Just (AST.Indexer Nothing (AST.NumericLiteral Nothing (Left index)) (AST.Var Nothing varName))) : il)
312−
313−emptyAnn :: Ann
314−emptyAnn = (SourceSpan "" (SourcePos 0 0) (SourcePos 0 0), [], Nothing, Nothing)
315−
316−arrayLength :: AST -> AST
317−arrayLength a = AST.App Nothing (AST.Var Nothing arrayLengthFn) [a]
318−-- arrayLength a = AST.Var Nothing (arrayLengthFn <> "(" <> prettyPrintIL1 a <> ")")
319−
320−copyDict :: AST -> AST
321−copyDict a = AST.App Nothing (AST.Var Nothing copyDictFn) [a]
src/CodeGen/IL/Common.hsdeleted−196
@@ -1,196 +0,0 @@
1−-- | Common code generation utility functions
2−module CodeGen.IL.Common where
3−
4−import Prelude.Compat
5−
6−import Control.Monad.Supply.Class (MonadSupply, freshName)
7−import Data.Char
8−import Data.Maybe (maybe)
9−import Data.Monoid ((<>))
10−import Data.Text (Text)
11−import qualified Data.Text as T
12−
13−import Language.PureScript.Crash
14−import Language.PureScript.Names
15−
16−import qualified Language.PureScript.Constants as C
17−
18−moduleNameToIL :: ModuleName -> Text
19−moduleNameToIL (ModuleName mn) =
20− let name = T.replace "." "_" mn
21− in if nameIsILBuiltIn name then (name <> moduleRenamerMarker) else name
22−
23−moduleNameToIL' :: ModuleName -> Text
24−moduleNameToIL' (ModuleName mn) = T.replace "_" "." mn
25−
26−-- | Convert an 'Ident' into a valid IL identifier:
27−--
28−-- * Alphanumeric characters are kept unmodified.
29−--
30−-- * Reserved IL identifiers are wrapped with '_'.
31−--
32−identToIL :: Ident -> Text
33−identToIL UnusedIdent = unusedName
34−identToIL (Ident "$__unused") = unusedName
35−identToIL (Ident name) | name == C.undefined = undefinedName -- Note: done in Printer.hs too
36−identToIL (Ident name) = properToIL name
37−identToIL (GenIdent _ _) = internalError "GenIdent in identToIL"
38−
39−moduleIdentToIL :: Ident -> Text
40−moduleIdentToIL UnusedIdent = unusedName
41−moduleIdentToIL (Ident name) | name == C.undefined = undefinedName
42−moduleIdentToIL (Ident name) = moduleProperToIL name
43−moduleIdentToIL (GenIdent _ _) = internalError "GenIdent in identToIL"
44−
45−undefinedName :: Text
46−undefinedName = "Undefined"
47−
48−unusedName :: Text
49−unusedName = "_"
50−
51−properToIL :: Text -> Text
52−properToIL name
53− | nameIsILReserved name = "ˉ" <> name
54− | otherwise = T.concatMap identCharToText name
55−
56−-- | Attempts to find a human-readable name for a symbol, if none has been specified returns the
57−-- ordinal value.
58−identCharToText :: Char -> Text
59−identCharToText 'ṩ' = "_ṩ"
60−identCharToText c | isAlphaNum c = T.singleton c
61−identCharToText '_' = "_"
62−identCharToText '\'' = "ꞌ" -- lowercase saltillo
63−identCharToText c = error (show (ord c)) -- TODO: should never occur now(?)
64−
65−moduleProperToIL :: Text -> Text
66−moduleProperToIL = T.concatMap identCharToText
67−
68−-- | Checks whether an identifier name is reserved in IL.
69−nameIsILReserved :: Text -> Bool
70−nameIsILReserved name =
71− name `elem` ilAnyReserved
72−
73−-- | Checks whether a name matches a built-in value in IL.
74−nameIsILBuiltIn :: Text -> Bool
75−nameIsILBuiltIn name =
76− name `elem`
77− [ "Any"
78− , "Apply"
79− , "Contains"
80− , "CopyDict"
81− , "Dict"
82− , "EffFn"
83− , "Fn"
84− , "Foreign"
85− , "Get"
86− , "Index"
87− , "Is"
88− , "Length"
89− , "Once"
90− , "Run"
91− , "Undefined"
92− ]
93−
94−ilAnyReserved :: [Text]
95−ilAnyReserved =
96− concat
97− [ ilKeywords
98− , ilLiterals
99− ]
100−
101−ilKeywords :: [Text]
102−ilKeywords =
103− [ "break"
104− , "case"
105− , "chan"
106− , "const"
107− , "continue"
108− , "default"
109− , "defer"
110− , "else"
111− , "fallthrough"
112− , "for"
113− , "func"
114− , "go"
115− , "goto"
116− , "if"
117− , "import"
118− , "interface"
119− , "map"
120− , "package"
121− , "range"
122− , "return"
123− , "select"
124− , "struct"
125− , "switch"
126− , "type"
127− , "var"
128− ]
129−
130−ilLiterals :: [Text]
131−ilLiterals =
132− [ "init"
133− , "nil"
134− , "int"
135− , "int8"
136− , "int16"
137− , "int32"
138− , "int64"
139− , "uint"
140− , "uint8"
141− , "uint16"
142− , "uint32"
143− , "uint64"
144− , "uintptr"
145− , "float32"
146− , "float64"
147− , "complex64"
148− , "complex128"
149− , "byte"
150− , "rune"
151− , "string"
152− ]
153−
154−withPrefix :: Text -> Text
155−withPrefix s = "Ꞌ" <> s -- uppercase saltillo
156−
157−anyType :: Text
158−anyType = "Any"
159−
160−dictType :: Text
161−dictType = "Dict"
162−
163−arrayType :: Text
164−arrayType = "[]" <> anyType
165−
166−uncurriedFnType :: Int -> Text
167−uncurriedFnType i = "Fn" <> (T.pack . show $ i)
168−
169−int :: Text
170−int = "int"
171−
172−float :: Text
173−float = "float64"
174−
175−bool :: Text
176−bool = "bool"
177−
178−string :: Text
179−string = "string"
180−
181−arrayLengthFn :: Text
182−arrayLengthFn = "Length"
183−
184−indexFn :: Text
185−indexFn = "Index"
186−
187−copyDictFn :: Text
188−copyDictFn = "CopyDict"
189−
190−freshName' :: MonadSupply m => m Text
191−freshName' = do
192− name <- freshName
193− return $ T.replace "$" "ṩ" name
194−
195−moduleRenamerMarker :: Text
196−moduleRenamerMarker = "__"
src/CodeGen/IL/Optimizer.hsdeleted−81
@@ -1,81 +0,0 @@
1−-- | This module optimizes code in the intermediate representation.
2−module CodeGen.IL.Optimizer (optimize) where
3−
4−import Prelude.Compat
5−
6−import Control.Monad.Supply.Class (MonadSupply)
7−import Data.Text (Text)
8−import Language.PureScript.CoreImp.AST
9−import Language.PureScript.CoreImp.Optimizer.Blocks
10−import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict)
11−import Language.PureScript.CoreImp.Optimizer.Inliner (etaConvert, evaluateIifes, inlineVariables, unThunk)
12−import Language.PureScript.CoreImp.Optimizer.Unused
13−
14−import CodeGen.IL.Common (unusedName)
15−import CodeGen.IL.Optimizer.Inliner
16−import CodeGen.IL.Optimizer.MagicDo
17−import CodeGen.IL.Optimizer.TCO
18−
19−import qualified Language.PureScript.Constants as C
20−
21−-- | Apply a series of optimizer passes to simplified IL code
22−optimize :: MonadSupply m => AST -> AST -> m AST
23−optimize mn il = do
24− il' <- untilFixedPoint (inlineFnComposition . inlineUnsafeCoerce . inlineUnsafePartial . tidyUp) il
25− il'' <- untilFixedPoint (return . ignoreUnusedResults . inlineCommonValues . inlineCommonOperators . tidyUp) . tco mn . inlineST
26− =<< untilFixedPoint (return . magicDoST)
27− =<< untilFixedPoint (return . magicDoEff)
28− =<< untilFixedPoint (return . magicDoEffect) il'
29− untilFixedPoint (return . collapseVarDeclarations) il''
30− where
31− tidyUp :: AST -> AST
32− tidyUp = applyAll
33− [ collapseNestedBlocks
34− , collapseNestedIfs
35− , collapseIfChecks
36− , removeCodeAfterReturnStatements
37− , unThunk
38− , etaConvert
39− , evaluateIifes
40− , inlineVariables
41− ]
42−
43−untilFixedPoint :: (Monad m, Eq a) => (a -> m a) -> a -> m a
44−untilFixedPoint f = go
45− where
46− go a = do
47− a' <- f a
48− if a' == a then return a' else go a'
49−
50−collapseIfChecks :: AST -> AST
51−collapseIfChecks = everywhere collapse where
52− collapse :: AST -> AST
53− collapse (IfElse _ (Binary _ EqualTo (BooleanLiteral _ True) (BooleanLiteral _ True)) (Block _ [exprs]) _) = exprs
54− collapse (IfElse _ (Binary _ EqualTo (Indexer _ (Var _ prop) (Var _ val)) (BooleanLiteral _ True)) (Block _ [exprs]) _)
55− | prop == "otherwise" && val == "Data_Boolean" = exprs
56− collapse exprs = exprs
57−
58−collapseVarDeclarations :: AST -> AST
59−collapseVarDeclarations = everywhere collapse where
60− collapse :: AST -> AST
61− collapse (Block ss sts) = Block ss (go Nothing sts)
62− collapse s = s
63−
64− go :: Maybe Text -> [AST] -> [AST]
65− go _ [] = []
66− go Nothing (decl@(VariableIntroduction _ var (Just _)) : sts) = decl : go (Just var) (go Nothing sts)
67− go (Just var') ((VariableIntroduction ss var (Just val)) : sts)
68− | var == var' = (Assignment ss (Var Nothing var) val) : go (Just var') sts
69− go var' (s:sts) = s : go var' sts
70−
71−ignoreUnusedResults :: AST -> AST
72−ignoreUnusedResults = everywhere $ removeFromBlock go
73− where
74− go :: [AST] -> [AST]
75− go [] = []
76− go (VariableIntroduction ss var (Just s) : sts)
77− | not $ any (everything (||) (isUsed var)) sts = sts'
78− where
79− sts' | App{} <- s = s : (go sts)
80− | otherwise = go sts
81− go (s:sts) = s : go sts
src/CodeGen/IL/Optimizer/Common.hsdeleted−18
@@ -1,18 +0,0 @@
1−-- | Common functions used by the various optimizer phases
2−module CodeGen.IL.Optimizer.Common where
3−
4−import Prelude.Compat
5−
6−import Data.Text (Text)
7−
8−import Language.PureScript.CoreImp.AST
9−import Language.PureScript.PSString (PSString, decodeString)
10−
11−isDict :: (Text, PSString) -> AST -> Bool
12−isDict (moduleName, dictName) (Indexer _ (Var _ x) (Var _ y)) =
13− Just x == decodeString dictName && y == moduleName
14−isDict _ _ = False
15−
16−isDict' :: [(Text, PSString)] -> AST -> Bool
17−isDict' xs il = any (`isDict` il) xs
18−
src/CodeGen/IL/Optimizer/Inliner.hsdeleted−435
@@ -1,435 +0,0 @@
1−-- | This module performs basic inlining of known functions
2−module CodeGen.IL.Optimizer.Inliner
3− ( inlineCommonValues
4− , inlineCommonOperators
5− , inlineFnComposition
6− , inlineUnsafeCoerce
7− , inlineUnsafePartial
8− ) where
9−
10−import Prelude.Compat
11−
12−import Control.Monad.Supply.Class (MonadSupply)
13−
14−import Data.Either (rights)
15−import Data.Maybe (fromMaybe)
16−import Data.String (IsString, fromString)
17−import Data.Text (Text)
18−import qualified Data.Text as T
19−
20−import Language.PureScript.PSString (PSString, decodeString, mkString)
21−import Language.PureScript.CoreImp.AST
22−import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict, isDict')
23−import Language.PureScript.AST (SourceSpan(..))
24−import qualified Language.PureScript.Constants as C
25−
26−import CodeGen.IL.Common
27−import CodeGen.IL.Optimizer.Common
28−
29−-- TODO: Potential bug:
30−-- Shouldn't just inline this case: { var x = 0; x.toFixed(10); }
31−-- Needs to be: { 0..toFixed(10); }
32−-- Probably needs to be fixed in pretty-printer instead.
33−shouldInline :: AST -> Bool
34−shouldInline (Var _ _) = True
35−shouldInline (NumericLiteral _ _) = True
36−shouldInline (StringLiteral _ _) = True
37−shouldInline (BooleanLiteral _ _) = True
38−shouldInline (Indexer _ index val) = shouldInline index && shouldInline val
39−shouldInline _ = False
40−
41−inlineCommonValues :: AST -> AST
42−inlineCommonValues = everywhere convert
43− where
44− convert :: AST -> AST
45− convert (App ss fn [dict])
46− | isDict' [semiringNumber, semiringInt] dict && isDict fnZero fn = NumericLiteral ss (Left 0)
47− | isDict' [semiringNumber, semiringInt] dict && isDict fnOne fn = NumericLiteral ss (Left 1)
48− | isDict boundedBoolean dict && isDict fnBottom fn = BooleanLiteral ss False
49− | isDict boundedBoolean dict && isDict fnTop fn = BooleanLiteral ss True
50− convert (App ss (App _ fn [dict]) [x])
51− | isDict ringInt dict && isDict fnNegate fn = Unary ss Negate (unbox x $ snd ringInt)
52− convert (App ss (App _ (App _ fn [dict]) [x]) [y])
53− | isDict semiringInt dict && isDict fnAdd fn = intOp ss Add semiringInt x y
54− | isDict semiringInt dict && isDict fnMultiply fn = intOp ss Multiply semiringInt x y
55− | isDict ringInt dict && isDict fnSubtract fn = intOp ss Subtract ringInt x y
56− convert other = other
57− fnZero = (C.dataSemiring, C.zero)
58− fnOne = (C.dataSemiring, C.one)
59− fnBottom = (C.dataBounded, C.bottom)
60− fnTop = (C.dataBounded, C.top)
61− fnAdd = (C.dataSemiring, C.add)
62− fnMultiply = (C.dataSemiring, C.mul)
63− fnSubtract = (C.dataRing, C.sub)
64− fnNegate = (C.dataRing, C.negate)
65− intOp ss op (_, d) x y = Binary ss op (unbox x d) (unbox y d)
66−
67−inlineCommonOperators :: AST -> AST
68−inlineCommonOperators = everywhereTopDown $ applyAll $
69− [ binary semiringNumber opAdd Add
70− , binary semiringNumber opMul Multiply
71−
72− , binary ringNumber opSub Subtract
73− , unary ringNumber opNegate Negate
74−
75− , binary euclideanRingNumber opDiv Divide
76−
77− -- , binary eqNumber opEq EqualTo
78− -- , binary eqNumber opNotEq NotEqualTo
79− , binary eqInt opEq EqualTo
80− , binary eqInt opNotEq NotEqualTo
81− , binary eqString opEq EqualTo
82− , binary eqString opNotEq NotEqualTo
83− , binary eqChar opEq EqualTo
84− , binary eqChar opNotEq NotEqualTo
85− , binary eqBoolean opEq EqualTo
86− , binary eqBoolean opNotEq NotEqualTo
87−
88− , binary ordBoolean opLessThan LessThan
89− , binary ordBoolean opLessThanOrEq LessThanOrEqualTo
90− , binary ordBoolean opGreaterThan GreaterThan
91− , binary ordBoolean opGreaterThanOrEq GreaterThanOrEqualTo
92− , binary ordChar opLessThan LessThan
93− , binary ordChar opLessThanOrEq LessThanOrEqualTo
94− , binary ordChar opGreaterThan GreaterThan
95− , binary ordChar opGreaterThanOrEq GreaterThanOrEqualTo
96− , binary ordInt opLessThan LessThan
97− , binary ordInt opLessThanOrEq LessThanOrEqualTo
98− , binary ordInt opGreaterThan GreaterThan
99− , binary ordInt opGreaterThanOrEq GreaterThanOrEqualTo
100− , binary ordNumber opLessThan LessThan
101− , binary ordNumber opLessThanOrEq LessThanOrEqualTo
102− , binary ordNumber opGreaterThan GreaterThan
103− , binary ordNumber opGreaterThanOrEq GreaterThanOrEqualTo
104− , binary ordString opLessThan LessThan
105− , binary ordString opLessThanOrEq LessThanOrEqualTo
106− , binary ordString opGreaterThan GreaterThan
107− , binary ordString opGreaterThanOrEq GreaterThanOrEqualTo
108−
109− , binary semigroupString opAppend Add
110−
111− , binary heytingAlgebraBoolean opConj And
112− , binary heytingAlgebraBoolean opDisj Or
113− , unary heytingAlgebraBoolean opNot Not
114−
115− , binary' C.dataIntBits C.or BitwiseOr
116− , binary' C.dataIntBits C.and BitwiseAnd
117− , binary' C.dataIntBits C.xor BitwiseXor
118− , binary' C.dataIntBits C.shl ShiftLeft
119− , binary' C.dataIntBits C.shr ShiftRight
120− , unary' C.dataIntBits C.complement BitwiseNot
121−
122− , inlineNonClassFunction (isModFn (C.dataFunction, C.apply)) $ \f x -> App Nothing f [x]
123− , inlineNonClassFunction (isModFn (C.dataFunction, C.applyFlipped)) $ \x f -> App Nothing f [x]
124− , inlineUnsafeIndex (isModFnWithDict (C.dataArray, C.unsafeIndex)) $ flip (Indexer Nothing)
125− ] ++
126− [ fn | i <- [0..10], fn <- [ mkFn i, runFn i ] ] ++
127− [ fn | i <- [0..10], fn <- [ mkEffFn C.controlMonadEffUncurried C.mkEffFn i, runEffFn C.controlMonadEffUncurried C.runEffFn i ] ] ++
128− [ fn | i <- [0..10], fn <- [ mkEffFn C.effectUncurried C.mkEffectFn i, runEffFn C.effectUncurried C.runEffectFn i ] ]
129− where
130− binary :: (Text, PSString) -> (Text, PSString) -> BinaryOperator -> AST -> AST
131− binary dict@(_, d) fns op = convert where
132− convert :: AST -> AST
133− convert (App ss (App _ (App _ fn [dict']) [x]) [y])
134− | isDict dict dict' && isDict fns fn = Binary ss op (unbox x d) (unbox y d)
135− convert other = other
136− binary' :: Text -> PSString -> BinaryOperator -> AST -> AST
137− binary' moduleName opString op = convert where
138− convert :: AST -> AST
139− convert (App ss (App _ fn [x]) [y]) | isDict (moduleName, opString) fn = Binary ss op (unbox x mn) (unbox y mn)
140− convert other = other
141− mn :: PSString
142− mn = mkString moduleName
143− unary :: (Text, PSString) -> (Text, PSString) -> UnaryOperator -> AST -> AST
144− unary dicts@(_, d) fns op = convert where
145− convert :: AST -> AST
146− convert (App ss (App _ fn [dict']) [x]) | isDict dicts dict' && isDict fns fn = Unary ss op (unbox x d)
147− convert other = other
148− unary' :: Text -> PSString -> UnaryOperator -> AST -> AST
149− unary' moduleName fnName op = convert where
150− convert :: AST -> AST
151− convert (App ss fn [x]) | isDict (moduleName, fnName) fn = Unary ss op (unbox x fnName)
152− convert other = other
153−
154− mkFn :: Int -> AST -> AST
155− mkFn = mkFn' C.dataFunctionUncurried C.mkFn $ \ss1 ss2 ss3 args il ->
156− Function ss1 Nothing args (Block ss2 [Return ss3 il])
157−
158− mkEffFn :: Text -> Text -> Int -> AST -> AST
159− mkEffFn modName fnName = mkFn' modName fnName $ \ss1 ss2 ss3 args il ->
160− Function ss1 Nothing args (Block ss2 [Return ss3 (App ss3 il [])])
161−
162− mkFn' :: Text -> Text -> (Maybe SourceSpan -> Maybe SourceSpan -> Maybe SourceSpan -> [Text] -> AST -> AST) -> Int -> AST -> AST
163− mkFn' modName fnName res 0 = convert where
164− convert :: AST -> AST
165− convert (App _ mkFnN [Function s1 Nothing [_] (Block s2 [Return s3 il])]) | isNFn modName fnName 0 mkFnN =
166− res s1 s2 s3 [] il
167− convert other = other
168− mkFn' modName fnName res n = convert where
169− convert :: AST -> AST
170− convert orig@(App ss mkFnN [fn]) | isNFn modName fnName n mkFnN =
171− case collectArgs n [] fn of
172− Just (args, [Return ss' ret]) -> res ss ss ss' args ret
173− _ -> orig
174− convert other = other
175− collectArgs :: Int -> [Text] -> AST -> Maybe ([Text], [AST])
176− collectArgs 1 acc (Function _ Nothing [oneArg] (Block _ il)) | length acc == n - 1 = Just (reverse (oneArg : acc), il)
177− collectArgs m acc (Function _ Nothing [oneArg] (Block _ [Return _ ret])) = collectArgs (m - 1) (oneArg : acc) ret
178− collectArgs _ _ _ = Nothing
179−
180− isNFn :: Text -> Text -> Int -> AST -> Bool
181− isNFn expectMod prefix n (Indexer _ (Var _ name) (Var _ modName)) | modName == expectMod =
182− name == fromString (T.unpack prefix <> show n)
183− isNFn _ _ _ _ = False
184−
185− runFn :: Int -> AST -> AST
186− runFn = runFn' C.dataFunctionUncurried C.runFn (\ss f args ->
187− let len = length args
188− typ = mkString $ uncurriedFnType len in
189− if len > 0
190− then App ss (App Nothing (StringLiteral Nothing typ) [f]) args
191− else App ss f args)
192− runEffFn :: Text -> Text -> Int -> AST -> AST
193− runEffFn modName fnName = runFn' modName fnName $ \ss fn acc ->
194− let typ = mkString . uncurriedFnType $ length acc in
195− Function ss Nothing [] (Block ss [Return ss (App ss (App Nothing (StringLiteral Nothing typ) [fn]) acc)])
196−
197− runFn' :: Text -> Text -> (Maybe SourceSpan -> AST -> [AST] -> AST) -> Int -> AST -> AST
198− runFn' modName runFnName res n = convert where
199− convert :: AST -> AST
200− convert il = fromMaybe il $ go n [] il
201−
202− go :: Int -> [AST] -> AST -> Maybe AST
203− go 0 acc (App ss runFnN [fn]) | isNFn modName runFnName n runFnN && length acc == n =
204− Just $ res ss fn acc
205− go m acc (App _ lhs [arg]) = go (m - 1) (arg : acc) lhs
206− go _ _ _ = Nothing
207−
208− inlineNonClassFunction :: (AST -> Bool) -> (AST -> AST -> AST) -> AST -> AST
209− inlineNonClassFunction p f = convert where
210− convert :: AST -> AST
211− convert (App _ (App _ op' [x]) [y]) | p op' = f x y
212− convert other = other
213−
214− inlineUnsafeIndex :: (AST -> Bool) -> (AST -> AST -> AST) -> AST -> AST
215− inlineUnsafeIndex p _ = convert where
216− convert :: AST -> AST
217− convert (App _ (App ss op' [x]) [y@NumericLiteral{}])
218− | p op' = Indexer ss y x
219− convert (App _ (App ss op' [x]) [y])
220− | p op' = App ss (Var Nothing indexFn) [x, y]
221− convert other = other
222−
223− isModFn :: (Text, PSString) -> AST -> Bool
224− isModFn (m, op) (Indexer _ (Var _ op') (Var _ m')) =
225− m == m' && decodeString op == Just op'
226− isModFn _ _ = False
227−
228− isModFnWithDict :: (Text, PSString) -> AST -> Bool
229− isModFnWithDict (m, op) (App _ (Indexer _ (Var _ op') (Var _ m')) [Var _ _]) =
230− m == m' && decodeString op == Just op'
231− isModFnWithDict _ _ = False
232−
233−-- (f <<< g $ x) = f (g x)
234−-- (f <<< g) = \x -> f (g x)
235−inlineFnComposition :: forall m. MonadSupply m => AST -> m AST
236−inlineFnComposition = everywhereTopDownM convert where
237− convert :: AST -> m AST
238− convert (App s1 (App s2 (App _ (App _ fn [dict']) [x]) [y]) [z])
239− | isFnCompose dict' fn = return $ App s1 x [App s2 y [z]]
240− | isFnComposeFlipped dict' fn = return $ App s2 y [App s1 x [z]]
241− convert app@(App ss (App _ (App _ fn [dict']) _) _)
242− | isFnCompose dict' fn || isFnComposeFlipped dict' fn = mkApps ss <$> goApps app <*> freshName'
243− convert other = return other
244−
245− mkApps :: Maybe SourceSpan -> [Either AST (Text, AST)] -> Text -> AST
246− mkApps ss fns a = App ss (Function ss Nothing [] (Block ss $ vars <> [Return Nothing comp])) []
247− where
248− vars = uncurry (VariableIntroduction ss) . fmap Just <$> rights fns
249− comp = Function ss Nothing [a] (Block ss [Return Nothing apps])
250− apps = foldr (\fn acc -> App ss (mkApp fn) [acc]) (Var ss a) fns
251−
252− mkApp :: Either AST (Text, AST) -> AST
253− mkApp = either id $ \(name, arg) -> Var (getSourceSpan arg) name
254−
255− goApps :: AST -> m [Either AST (Text, AST)]
256− goApps (App _ (App _ (App _ fn [dict']) [x]) [y])
257− | isFnCompose dict' fn = mappend <$> goApps x <*> goApps y
258− | isFnComposeFlipped dict' fn = mappend <$> goApps y <*> goApps x
259− goApps app@(App {}) = pure . Right . (,app) <$> freshName'
260− goApps other = pure [Left other]
261−
262− isFnCompose :: AST -> AST -> Bool
263− isFnCompose dict' fn = isDict semigroupoidFn dict' && isDict fnCompose fn
264−
265− isFnComposeFlipped :: AST -> AST -> Bool
266− isFnComposeFlipped dict' fn = isDict semigroupoidFn dict' && isDict fnComposeFlipped fn
267−
268− fnCompose :: forall a b. (IsString a, IsString b) => (a, b)
269− fnCompose = (C.controlSemigroupoid, C.compose)
270−
271− fnComposeFlipped :: forall a b. (IsString a, IsString b) => (a, b)
272− fnComposeFlipped = (C.controlSemigroupoid, C.composeFlipped)
273−
274−inlineUnsafeCoerce :: AST -> AST
275−inlineUnsafeCoerce = everywhereTopDown convert where
276− convert (App _ (Indexer _ (Var _ unsafeCoerceFn) (Var _ unsafeCoerce)) [ comp ])
277− | unsafeCoerceFn == C.unsafeCoerceFn && unsafeCoerce == C.unsafeCoerce
278− = comp
279− convert other = other
280−
281−inlineUnsafePartial :: AST -> AST
282−inlineUnsafePartial = everywhereTopDown convert where
283− convert (App ss fn [ comp ])
284− | isDict fnUnsafePartial fn
285− = App ss comp []
286− where
287− fnUnsafePartial :: forall a b. (IsString a, IsString b) => (a, b)
288− fnUnsafePartial = (C.partialUnsafe, C.unsafePartial)
289− convert other = other
290−
291−semiringNumber :: forall a b. (IsString a, IsString b) => (a, b)
292−semiringNumber = (C.dataSemiring, C.semiringNumber)
293−
294−semiringInt :: forall a b. (IsString a, IsString b) => (a, b)
295−semiringInt = (C.dataSemiring, C.semiringInt)
296−
297−ringNumber :: forall a b. (IsString a, IsString b) => (a, b)
298−ringNumber = (C.dataRing, C.ringNumber)
299−
300−ringInt :: forall a b. (IsString a, IsString b) => (a, b)
301−ringInt = (C.dataRing, C.ringInt)
302−
303−euclideanRingNumber :: forall a b. (IsString a, IsString b) => (a, b)
304−euclideanRingNumber = (C.dataEuclideanRing, C.euclideanRingNumber)
305−
306−-- eqNumber :: forall a b. (IsString a, IsString b) => (a, b)
307−-- eqNumber = (C.dataEq, C.eqNumber)
308−
309−eqInt :: forall a b. (IsString a, IsString b) => (a, b)
310−eqInt = (C.dataEq, C.eqInt)
311−
312−eqString :: forall a b. (IsString a, IsString b) => (a, b)
313−eqString = (C.dataEq, C.eqString)
314−
315−eqChar :: forall a b. (IsString a, IsString b) => (a, b)
316−eqChar = (C.dataEq, C.eqChar)
317−
318−eqBoolean :: forall a b. (IsString a, IsString b) => (a, b)
319−eqBoolean = (C.dataEq, C.eqBoolean)
320−
321−ordBoolean :: forall a b. (IsString a, IsString b) => (a, b)
322−ordBoolean = (C.dataOrd, C.ordBoolean)
323−
324−ordNumber :: forall a b. (IsString a, IsString b) => (a, b)
325−ordNumber = (C.dataOrd, C.ordNumber)
326−
327−ordInt :: forall a b. (IsString a, IsString b) => (a, b)
328−ordInt = (C.dataOrd, C.ordInt)
329−
330−ordString :: forall a b. (IsString a, IsString b) => (a, b)
331−ordString = (C.dataOrd, C.ordString)
332−
333−ordChar :: forall a b. (IsString a, IsString b) => (a, b)
334−ordChar = (C.dataOrd, C.ordChar)
335−
336−semigroupString :: forall a b. (IsString a, IsString b) => (a, b)
337−semigroupString = (C.dataSemigroup, C.semigroupString)
338−
339−boundedBoolean :: forall a b. (IsString a, IsString b) => (a, b)
340−boundedBoolean = (C.dataBounded, C.boundedBoolean)
341−
342−heytingAlgebraBoolean :: forall a b. (IsString a, IsString b) => (a, b)
343−heytingAlgebraBoolean = (C.dataHeytingAlgebra, C.heytingAlgebraBoolean)
344−
345−semigroupoidFn :: forall a b. (IsString a, IsString b) => (a, b)
346−semigroupoidFn = (C.controlSemigroupoid, C.semigroupoidFn)
347−
348−opAdd :: forall a b. (IsString a, IsString b) => (a, b)
349−opAdd = (C.dataSemiring, C.add)
350−
351−opMul :: forall a b. (IsString a, IsString b) => (a, b)
352−opMul = (C.dataSemiring, C.mul)
353−
354−opEq :: forall a b. (IsString a, IsString b) => (a, b)
355−opEq = (C.dataEq, C.eq)
356−
357−opNotEq :: forall a b. (IsString a, IsString b) => (a, b)
358−opNotEq = (C.dataEq, C.notEq)
359−
360−opLessThan :: forall a b. (IsString a, IsString b) => (a, b)
361−opLessThan = (C.dataOrd, C.lessThan)
362−
363−opLessThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)
364−opLessThanOrEq = (C.dataOrd, C.lessThanOrEq)
365−
366−opGreaterThan :: forall a b. (IsString a, IsString b) => (a, b)
367−opGreaterThan = (C.dataOrd, C.greaterThan)
368−
369−opGreaterThanOrEq :: forall a b. (IsString a, IsString b) => (a, b)
370−opGreaterThanOrEq = (C.dataOrd, C.greaterThanOrEq)
371−
372−opAppend :: forall a b. (IsString a, IsString b) => (a, b)
373−opAppend = (C.dataSemigroup, C.append)
374−
375−opSub :: forall a b. (IsString a, IsString b) => (a, b)
376−opSub = (C.dataRing, C.sub)
377−
378−opNegate :: forall a b. (IsString a, IsString b) => (a, b)
379−opNegate = (C.dataRing, C.negate)
380−
381−opDiv :: forall a b. (IsString a, IsString b) => (a, b)
382−opDiv = (C.dataEuclideanRing, C.div)
383−
384−opConj :: forall a b. (IsString a, IsString b) => (a, b)
385−opConj = (C.dataHeytingAlgebra, C.conj)
386−
387−opDisj :: forall a b. (IsString a, IsString b) => (a, b)
388−opDisj = (C.dataHeytingAlgebra, C.disj)
389−
390−opNot :: forall a b. (IsString a, IsString b) => (a, b)
391−opNot = (C.dataHeytingAlgebra, C.not)
392−
393−unbox :: AST -> PSString -> AST
394−unbox e d = select . inlineCommonValues $ inlineCommonOperators e
395− where
396− select :: AST -> AST
397− select e' =
398− case e' of
399− Var{} -> unbox' e'
400− App{} -> unbox' e'
401− Indexer{} -> unbox' e'
402− _ -> e'
403− unbox' :: AST -> AST
404− unbox' e' = maybe e' (\t -> App Nothing (StringLiteral Nothing t) [e']) $ unboxType d
405−
406−unboxType :: PSString -> Maybe PSString
407−unboxType s = do
408− t <- decodeString s
409− t' <- unboxType' t
410− return $ mkString t'
411− where
412− unboxType' :: Text -> Maybe Text
413− unboxType' t
414− | t == C.eqInt ||
415− t == C.semiringInt ||
416− t == C.ringInt ||
417− t == C.ordInt ||
418− t == C.dataIntBits
419− = Just int
420− | t == C.semiringNumber ||
421− t == C.ringNumber ||
422− t == C.ordNumber ||
423− t == C.euclideanRingNumber
424− = Just float
425− | t == C.eqBoolean ||
426− t == C.ordBoolean ||
427− t == C.heytingAlgebraBoolean
428− = Just bool
429− | t == C.eqChar ||
430− t == C.eqString ||
431− t == C.ordChar ||
432− t == C.ordString ||
433− t == C.semigroupString
434− = Just string
435− | otherwise = Nothing
src/CodeGen/IL/Optimizer/MagicDo.hsdeleted−146
@@ -1,146 +0,0 @@
1−-- | This module implements the "Magic Do" optimization, which inlines calls to return
2−-- and bind for the Eff monad, as well as some of its actions.
3−module CodeGen.IL.Optimizer.MagicDo (magicDoEffect, magicDoEff, magicDoST, inlineST) where
4−
5−import Prelude.Compat
6−import Protolude (ordNub)
7−
8−import Data.Maybe (fromJust, isJust)
9−import Data.Text (Text)
10−
11−import Language.PureScript.CoreImp.AST
12−import Language.PureScript.CoreImp.Optimizer.Common hiding (isDict)
13−import Language.PureScript.PSString (PSString, decodeString, mkString)
14−import qualified Language.PureScript.Constants as C
15−
16−import CodeGen.IL.Common (undefinedName, unusedName)
17−import CodeGen.IL.Optimizer.Common
18−
19−-- | Inline type class dictionaries for >>= and return for the Eff monad
20−--
21−-- E.g.
22−--
23−-- Prelude[">>="](dict)(m1)(function(x) {
24−-- return ...;
25−-- })
26−--
27−-- becomes
28−--
29−-- function __do {
30−-- var x = m1();
31−-- ...
32−-- }
33−magicDoEff :: AST -> AST
34−magicDoEff = magicDo C.eff C.effDictionaries
35−
36−magicDoEffect :: AST -> AST
37−magicDoEffect = magicDo C.effect C.effectDictionaries
38−
39−magicDoST :: AST -> AST
40−magicDoST = magicDo C.st C.stDictionaries
41−
42−magicDo :: Text -> C.EffectDictionaries -> AST -> AST
43−magicDo effectModule C.EffectDictionaries{..} = everywhereTopDown convert
44− where
45− -- Desugar monomorphic calls to >>= and return for the Eff monad
46− convert :: AST -> AST
47− -- Desugar pure
48− convert (App _ (App _ pure' [val]) []) | isPure pure' = val
49− -- Desugar discard
50− convert (App _ (App _ bind [m]) [Function s1 Nothing [unused] (Block s2 il)]) | isDiscard bind && unused == unusedName =
51− Function s1 Nothing [] $ Block s2 (App s2 m [] : map applyReturns il )
52− -- Desugar bind
53− convert (App _ (App _ bind [m]) [Function s1 Nothing [arg] (Block s2 il)]) | isBind bind =
54− Function s1 Nothing [] $ Block s2 (VariableIntroduction s2 arg (Just (App s2 m [])) : map applyReturns il)
55− -- Desugar untilE
56− convert (App s1 (App _ f [arg]) []) | isEffFunc edUntil f =
57− App s1 (Function s1 Nothing [] (Block s1 [ While s1 (Unary s1 Not (App s1 arg [])) (Block s1 []), Return s1 $ ObjectLiteral s1 []])) []
58− -- Desugar whileE
59− convert (App _ (App _ (App s1 f [arg1]) [arg2]) []) | isEffFunc edWhile f =
60− App s1 (Function s1 Nothing [] (Block s1 [ While s1 (App s1 arg1 []) (Block s1 [ App s1 arg2 [] ]), Return s1 $ ObjectLiteral s1 []])) []
61− -- -- Inline __do returns
62− -- convert (Return _ (App _ (Function _ (Just ident) [] body) [])) | ident == fnName = body
63− -- Inline double applications
64− convert (App _ (App s1 (Function s2 Nothing [] (Block ss body)) []) []) =
65− App s1 (Function s2 Nothing [] (Block ss (applyReturns `fmap` body))) []
66− convert other = other
67− -- Check if an expression represents a monomorphic call to >>= for the Eff monad
68− isBind (App _ fn [dict]) | isDict (effectModule, edBindDict) dict && isBindPoly fn = True
69− isBind _ = False
70− -- Check if an expression represents a call to @discard@
71− isDiscard (App _ (App _ fn [dict1]) [dict2])
72− | isDict (C.controlBind, C.discardUnitDictionary) dict1 &&
73− isDict (effectModule, edBindDict) dict2 &&
74− isDiscardPoly fn = True
75− isDiscard _ = False
76−
77− -- Check if an expression represents a monomorphic call to pure or return for the Eff applicative
78− isPure (App _ fn [dict]) | isDict (effectModule, edApplicativeDict) dict && isPurePoly fn = True
79− isPure _ = False
80− -- Check if an expression represents the polymorphic >>= function
81− isBindPoly = isDict (C.controlBind, C.bind)
82− -- Check if an expression represents the polymorphic pure function
83− isPurePoly = isDict (C.controlApplicative, C.pure')
84− -- Check if an expression represents the polymorphic discard function
85− isDiscardPoly = isDict (C.controlBind, C.discard)
86− -- Check if an expression represents a function in the Effect module
87− isEffFunc name (Indexer _ (StringLiteral _ name') (Var _ eff)) = eff == effectModule && name == name'
88− isEffFunc _ _ = False
89−
90− applyReturns :: AST -> AST
91− applyReturns (Return ss ret) = Return ss (App ss ret [])
92− applyReturns (Block ss ils) = Block ss (map applyReturns ils)
93− applyReturns (While ss cond il) = While ss cond (applyReturns il)
94− applyReturns (For ss v lo hi il) = For ss v lo hi (applyReturns il)
95− applyReturns (ForIn ss v xs il) = ForIn ss v xs (applyReturns il)
96− applyReturns (IfElse ss cond t f) = IfElse ss cond (applyReturns t) (applyReturns `fmap` f)
97− applyReturns other = other
98−
99−-- | Inline functions in the ST module
100−inlineST :: AST -> AST
101−inlineST = everywhere convertBlock
102− where
103− -- Look for runST blocks and inline the STRefs there.
104− -- If all STRefs are used in the scope of the same runST, only using { read, write, modify }STRef then
105− -- we can be more aggressive about inlining, and actually turn STRefs into local variables.
106− convertBlock (App s1 f [arg]) | isSTFunc C.runST f =
107− let refs = ordNub . findSTRefsIn $ arg
108− usages = findAllSTUsagesIn arg
109− allUsagesAreLocalVars = all (\u -> let v = toVar u in isJust v && fromJust v `elem` refs) usages
110− localVarsDoNotEscape = all (\r -> length (r `appearingIn` arg) == length (filter (\u -> let v = toVar u in v == Just r) usages)) refs
111− in App s1 (everywhere (convert (allUsagesAreLocalVars && localVarsDoNotEscape)) arg) []
112− convertBlock other = other
113− -- Convert a block in a safe way, preserving object wrappers of references,
114− -- or in a more aggressive way, turning wrappers into local variables depending on the
115− -- agg(ressive) parameter.
116− convert agg (App s1 f [arg]) | isSTFunc C.newSTRef f =
117− Function s1 Nothing [] (Block s1 [Return s1 $ if agg then arg else ObjectLiteral s1 [(mkString C.stRefValue, arg)]])
118− convert agg (App _ (App s1 f [ref]) []) | isSTFunc C.readSTRef f =
119− if agg then ref else Indexer s1 (StringLiteral s1 C.stRefValue) ref
120− convert agg (App _ (App _ (App s1 f [arg]) [ref]) []) | isSTFunc C.writeSTRef f =
121− if agg then Assignment s1 ref arg else Assignment s1 (Indexer s1 (StringLiteral s1 C.stRefValue) ref) arg
122− convert agg (App _ (App _ (App s1 f [func]) [ref]) []) | isSTFunc C.modifySTRef f =
123− if agg then Assignment s1 ref (App s1 func [ref]) else Assignment s1 (Indexer s1 (StringLiteral s1 C.stRefValue) ref) (App s1 func [Indexer s1 (StringLiteral s1 C.stRefValue) ref])
124− convert _ other = other
125− -- Check if an expression represents a function in the ST module
126− isSTFunc name (Indexer _ (StringLiteral _ name') (Var _ st)) = st == C.st && name == name'
127− isSTFunc _ _ = False
128− -- Find all ST Refs initialized in this block
129− findSTRefsIn = everything (++) isSTRef
130− where
131− isSTRef (VariableIntroduction _ ident (Just (App _ (App _ f [_]) []))) | isSTFunc C.newSTRef f = [ident]
132− isSTRef _ = []
133− -- Find all STRefs used as arguments to readSTRef, writeSTRef, modifySTRef
134− findAllSTUsagesIn = everything (++) isSTUsage
135− where
136− isSTUsage (App _ (App _ f [ref]) []) | isSTFunc C.readSTRef f = [ref]
137− isSTUsage (App _ (App _ (App _ f [_]) [ref]) []) | isSTFunc C.writeSTRef f || isSTFunc C.modifySTRef f = [ref]
138− isSTUsage _ = []
139− -- Find all uses of a variable
140− appearingIn ref = everything (++) isVar
141− where
142− isVar e@(Var _ v) | v == ref = [e]
143− isVar _ = []
144− -- Convert a AST value to a String if it is a Var
145− toVar (Var _ v) = Just v
146− toVar _ = Nothing
src/CodeGen/IL/Optimizer/TCO.hsdeleted−141
@@ -1,141 +0,0 @@
1−module CodeGen.IL.Optimizer.TCO (tco, tcoLoop) where
2−
3−import Prelude.Compat
4−
5−import Data.Text (Text)
6−import Data.Monoid ((<>))
7−import Language.PureScript.CoreImp.AST
8−import Language.PureScript.AST.SourcePos (SourceSpan)
9−import Safe (headDef, tailSafe)
10−import CodeGen.IL.Common
11−
12−import qualified Language.PureScript.Constants as C
13−
14−tcoLoop :: Text
15−tcoLoop = "ṩtco_loop"
16−
17−tco :: AST -> AST -> AST
18−tco mn = everywhere convert where
19− tcoVar :: Text -> Text
20− tcoVar arg = "ṩtco_var_" <> arg
21−
22− copyVar :: Text -> Text
23− copyVar arg = "ṩcopy_" <> arg
24−
25− tcoDone :: Text
26− tcoDone = "ṩtco_done"
27−
28− tcoResult :: Text
29− tcoResult = "ṩtco_result"
30−
31− convert :: AST -> AST
32− convert fn@(Function ss (Just name) args _)
33− | isTailRecursive name body'
34− = replace (toLoop name outerArgs innerArgs body')
35− where
36− innerArgs = headDef [] argss
37− outerArgs = concat . reverse $ tailSafe argss
38− (argss, body', replace) = collectAllFunctionArgs [] id fn
39− convert (Assignment ss (Var _ name) fn@(Function _ Nothing _ _))
40− | isTailRecursive name body'
41− = Assignment ss (Var ss name) (replace (toLoop name outerArgs innerArgs body'))
42− where
43− innerArgs = headDef [] argss
44− outerArgs = concat . reverse $ tailSafe argss
45− (argss, body', replace) = collectAllFunctionArgs [] id fn
46− convert js = js
47−
48− collectAllFunctionArgs :: [[Text]] -> (AST -> AST) -> AST -> ([[Text]], AST, AST -> AST)
49− collectAllFunctionArgs allArgs f (Function s1 ident args (Block s2 (body@(Return _ _):_))) =
50− collectAllFunctionArgs (args : allArgs) (\b -> f (Function s1 ident (map copyVar args) (Block s2 [b]))) body
51− collectAllFunctionArgs allArgs f (Function ss ident args body@(Block _ _)) =
52− (args : allArgs, body, f . Function ss ident (map copyVar args))
53− collectAllFunctionArgs allArgs f (Return s1 (Function s2 ident args (Block s3 [body]))) =
54− collectAllFunctionArgs (args : allArgs) (\b -> f (Return s1 (Function s2 ident (map copyVar args) (Block s3 [b])))) body
55− collectAllFunctionArgs allArgs f (Return s1 (Function s2 ident args body@(Block _ _))) =
56− (args : allArgs, body, f . Return s1 . Function s2 ident (map copyVar args))
57− collectAllFunctionArgs allArgs f body = (allArgs, body, f)
58−
59− isTailRecursive :: Text -> AST -> Bool
60− isTailRecursive ident js = countSelfReferences js > 0 && allInTailPosition js where
61− countSelfReferences = everything (+) match where
62− match :: AST -> Int
63− match (Var _ ident') | ident == ident' = 1
64− match _ = 0
65−
66− allInTailPosition (Return _ expr)
67− | isSelfCall ident expr = countSelfReferences expr == 1
68− | otherwise = countSelfReferences expr == 0
69− allInTailPosition (While _ js1 body)
70− = countSelfReferences js1 == 0 && allInTailPosition body
71− allInTailPosition (For _ _ js1 js2 body)
72− = countSelfReferences js1 == 0 && countSelfReferences js2 == 0 && allInTailPosition body
73− allInTailPosition (ForIn _ _ js1 body)
74− = countSelfReferences js1 == 0 && allInTailPosition body
75− allInTailPosition (IfElse _ js1 body el)
76− = countSelfReferences js1 == 0 && allInTailPosition body && all allInTailPosition el
77− allInTailPosition (Block _ body)
78− = all allInTailPosition body
79− allInTailPosition (Throw _ js1)
80− = countSelfReferences js1 == 0
81− allInTailPosition (ReturnNoResult _)
82− = True
83− allInTailPosition (VariableIntroduction _ _ js1)
84− = all ((== 0) . countSelfReferences) js1
85− allInTailPosition (Assignment _ _ js1)
86− = countSelfReferences js1 == 0
87− allInTailPosition (Comment _ _ js1)
88− = allInTailPosition js1
89− allInTailPosition _
90− = False
91−
92− toLoop :: Text -> [Text] -> [Text] -> AST -> AST
93− toLoop ident outerArgs innerArgs js =
94− Block rootSS $
95− concatMap (\arg -> [ VariableIntroduction rootSS (tcoVar arg) . Just $
96− Var rootSS (copyVar arg) ]) (outerArgs ++ innerArgs) ++
97− [ Assignment rootSS (Var rootSS $ "var " <> tcoDone) $ BooleanLiteral Nothing False
98− , VariableIntroduction rootSS tcoResult Nothing
99− , Assignment rootSS (Var rootSS $ "var " <> tcoLoop) (Function rootSS (Just tcoLoop) (outerArgs ++ innerArgs) (Block rootSS [loopify js]))
100− , While rootSS (Unary Nothing Not (Var rootSS tcoDone))
101− (Block rootSS
102− [(Assignment rootSS (Var rootSS tcoResult) (App rootSS (Var rootSS tcoLoop) ((map (Var rootSS . tcoVar) outerArgs) ++ (map (Var rootSS . copyVar) innerArgs))))])
103− , Return rootSS (Var rootSS tcoResult)
104− ]
105− where
106− rootSS = Nothing
107−
108− loopify :: AST -> AST
109− loopify (Return ss ret)
110− | isSelfCall ident ret =
111− let
112− allArgumentValues = concat $ collectArgs [] ret
113− in
114− Block ss $
115− zipWith (\val arg ->
116− Assignment ss (Var ss (tcoVar arg)) val) allArgumentValues outerArgs
117− ++ zipWith (\val arg ->
118− Assignment ss (Var ss (copyVar arg)) val) (drop (length outerArgs) allArgumentValues) innerArgs
119− ++ [ ReturnNoResult ss ]
120− | otherwise = Block ss [ markDone ss, Return ss ret ]
121− loopify (ReturnNoResult ss) = Block ss [ markDone ss, ReturnNoResult ss ]
122− loopify (While ss cond body) = While ss cond (loopify body)
123− loopify (For ss i js1 js2 body) = For ss i js1 js2 (loopify body)
124− loopify (ForIn ss i js1 body) = ForIn ss i js1 (loopify body)
125− loopify (IfElse ss cond body el) = IfElse ss cond (loopify body) (fmap loopify el)
126− loopify (Block ss body) = Block ss (map loopify body)
127− loopify other = other
128−
129− markDone :: Maybe SourceSpan -> AST
130− markDone ss = Assignment ss (Var ss tcoDone) (BooleanLiteral ss True)
131−
132− collectArgs :: [[AST]] -> AST -> [[AST]]
133− collectArgs acc (App _ fn args') = collectArgs (args' : acc) fn
134− collectArgs acc _ = acc
135−
136− isSelfCall :: Text -> AST -> Bool
137− isSelfCall ident (App _ (Var _ ident') _) = ident == ident'
138− isSelfCall ident (App _ (Indexer _ (Var _ ident') (Var _ mn')) _) = mn' == "" && ident == ident'
139− isSelfCall ident (App _ (Indexer _ (Var _ ident') mn') _) = mn' == mn && ident == ident'
140− isSelfCall ident (App _ fn _) = isSelfCall ident fn
141− isSelfCall _ _ = False
src/CodeGen/IL/Printer.hsdeleted−527
@@ -1,527 +0,0 @@
1−-- | Pretty printer for the AST
2−module CodeGen.IL.Printer
3− ( prettyPrintIL
4− , prettyPrintIL1
5− , prettyPrintILWithSourceMaps
6− , interfaceSource
7− , implHeaderSource
8− , implFooterSource
9− , isLiteral
10− , modLabel
11− , modPrefix
12− , ffiLoader
13− ) where
14−
15−import Prelude.Compat
16−
17−import Control.Arrow ((<+>))
18−import Control.Monad (forM, mzero)
19−import Control.Monad.State (StateT, evalStateT)
20−import Control.PatternArrows
21−import Data.List (filter, (\\))
22−import qualified Control.Arrow as A
23−
24−import Data.Maybe (fromMaybe)
25−import Data.Monoid ((<>))
26−import Data.Text (Text)
27−import qualified Data.Text as T
28−
29−import Language.PureScript.AST (SourceSpan(..))
30−import Language.PureScript.CoreImp.AST
31−import Language.PureScript.Comments
32−import Language.PureScript.Crash
33−import Language.PureScript.Names (Ident, runIdent)
34−import Language.PureScript.Pretty.Common
35−import Language.PureScript.PSString (PSString, decodeString, mkString)
36−
37−import CodeGen.IL.Common
38−import CodeGen.IL.Optimizer.TCO (tcoLoop)
39−
40−import qualified Language.PureScript.Constants as C
41−
42−-- TODO (Christoph): Get rid of T.unpack / pack
43−
44−literals :: (Emit gen) => Pattern PrinterState AST gen
45−literals = mkPattern' match'
46− where
47− match' :: (Emit gen) => AST -> StateT PrinterState Maybe gen
48− match' il = (addMapping' (getSourceSpan il) <>) <$> match il
49−
50− match :: (Emit gen) => AST -> StateT PrinterState Maybe gen
51− match (NumericLiteral _ n) = return $ emit $ T.pack $ either show show n
52− match (StringLiteral _ s) = return $ emit $ stringLiteral s
53− match (BooleanLiteral _ True) = return $ emit "true"
54− match (BooleanLiteral _ False) = return $ emit "false"
55− match (ArrayLiteral _ xs) = mconcat <$> sequence
56− [ return . emit $ arrayType <> "{"
57− , intercalate (emit ", ") <$> forM xs prettyPrintIL'
58− , return $ emit "}"
59− ]
60− -- match (ObjectLiteral _ []) = return $ emit "std::initializer_list<std::pair<const string, boxed>>{}"
61− match (ObjectLiteral _ ps) = mconcat <$> sequence
62− [ return . emit $ dictType <> "{"
63− , withIndent $ do
64− ils <- forM ps $ \(key, value) -> do
65− value' <- prettyPrintIL' value
66− return $ objectPropertyToString key <> value'
67− return $ intercalate (emit " ") $ map (<> emit ",") ils
68− , return $ emit "}"
69− ]
70− where
71− objectPropertyToString :: (Emit gen) => PSString -> gen
72− objectPropertyToString s = emit $ stringLiteral s <> ": "
73− match (Block _ sts) = mconcat <$> sequence
74− [ return $ emit "{\n"
75− , withIndent $ prettyStatements sts
76− , return $ emit "\n"
77− , currentIndent
78− , return $ emit "}"
79− ]
80− match (Var _ ident) | ident == C.undefined = return $ emit undefinedName
81− match (Var _ ident) = return $ emit ident
82− match (VariableIntroduction _ ident value) = mconcat <$> sequence
83− [ return . emit $ varDecl <> " " <> ident <> " " <> anyType
84− , maybe (return mempty) (fmap (emit " = " <>) . prettyPrintIL') value
85− ]
86− match (Assignment _ target value) = mconcat <$> sequence
87− [ prettyPrintIL' target
88− , return $ emit " = "
89− , prettyPrintIL' value
90− ]
91− match (App _ val []) = mconcat <$> sequence
92− [ return $ emit "Run("
93− , prettyPrintIL' val
94− , return $ emit ")"
95− ]
96− match (App _ (StringLiteral _ u) [arg])
97− | Just ty <- decodeString u = mconcat <$> sequence
98− [ prettyPrintIL' arg
99− , return $ emit ".("
100− , return $ emit ty
101− , return $ emit ")"
102− ]
103− match (App _ (Var _ fn) [arg]) | fn == arrayLengthFn = mconcat <$> sequence
104− [ return $ emit fn
105− , return $ emit "("
106− , prettyPrintIL' arg
107− , return $ emit ")"
108− ]
109− match (App _ (Var _ fn) args) | fn == indexFn = mconcat <$> sequence
110− [ return $ emit fn
111− , return $ emit "("
112− , intercalate (emit ", ") <$> forM args prettyPrintIL'
113− , return $ emit ")"
114− ]
115− match (App _ (Var _ fn) args) | fn == tcoLoop = mconcat <$> sequence
116− [ return $ emit fn
117− , return $ emit "("
118− , intercalate (emit ", ") <$> forM args prettyPrintIL'
119− , return $ emit ")"
120− ]
121− match (App _ (App Nothing (StringLiteral Nothing fnx) [fn@Function{}]) args)
122− | Just ftype <- decodeString fnx
123− , "Fn" `T.isPrefixOf` ftype = mconcat <$> sequence
124− [ prettyPrintIL' fn
125− , return $ emit "("
126− , intercalate (emit ", ") <$> forM args prettyPrintIL'
127− , return $ emit ")"
128− ]
129− match (App _ (App Nothing (StringLiteral Nothing fnx) [fn]) args)
130− | Just ftype <- decodeString fnx
131− , "Fn" `T.isPrefixOf` ftype = mconcat <$> sequence
132− [ prettyPrintIL' fn
133− , return $ emit ".("
134− , return $ emit ftype
135− , return $ emit ")("
136− , intercalate (emit ", ") <$> forM args prettyPrintIL'
137− , return $ emit ")"
138− ]
139− match app@(App{})
140− | (val, args) <- unApp app []
141− , length args > 1
142− = mconcat <$> sequence
143− [ return $ emit "Apply("
144− , prettyPrintIL' val
145− , return $ emit ", "
146− , intercalate (emit ", ") <$> forM args prettyPrintIL'
147− , return $ emit ")"
148− ]
149− match (App _ val args) = mconcat <$> sequence
150− [ return $ emit "Apply("
151− , prettyPrintIL' val
152− , return $ emit ", "
153− , intercalate (emit ", ") <$> forM args prettyPrintIL'
154− , return $ emit ")"
155− ]
156− match (Function _ (Just name) [] (Block _ [Return _ ret]))
157− | isComplexLiteral ret = mconcat <$> sequence
158− [ return $ emit "\n"
159− , return . emit $ varDecl <> " " <> initName name <> " Once\n"
160− , prettyPrintIL' $ VariableIntroduction Nothing (valueName name) Nothing
161− , return $ emit "\n\n"
162− , return $ emit "func "
163− , return . emit $ withPrefix name
164− , return . emit $ "() " <> anyType <> " "
165− , return $ emit "{\n"
166− , withIndent $ do
167− indentString <- currentIndent
168− return $ indentString <> (emit $ initName name <> ".Do(func() {\n") <>
169− indentString <> indentString <> (emit $ valueName name <> " = ")
170− , withIndent $ do
171− case ret of
172− Function _ Nothing args body -> mconcat <$> sequence
173− [ return $ emit "func("
174− , return . emit $ intercalate ", " (renderArg anyType <$> args)
175− , return . emit $ ") " <> anyType <> " "
176− , prettyPrintIL' body
177− ]
178− _ -> do
179− prettyPrintIL' ret
180− , return $ emit "\n"
181− , withIndent $ do
182− indentString <- currentIndent
183− return $ indentString <> (emit $ "})\n" <> "return " <> valueName name <>"\n")
184− , return $ emit "}\n\n"
185− ]
186− match (Function _ (Just name) [] ret) = mconcat <$> sequence
187− [ return $ emit "func "
188− , return . emit $ withPrefix name
189− , return . emit $ "() " <> anyType <> " "
190− , prettyPrintIL' ret
191− ]
192− match (Function _ _ args ret) = mconcat <$> sequence
193− [ return $ emit "func("
194− , return . emit $ intercalate ", " (renderArg anyType <$> args)
195− , return . emit $ ") " <> anyType <> " "
196− , prettyPrintIL' ret
197− ]
198− match (Indexer _ (Var _ name) (Var _ "")) = mconcat <$> sequence
199− [ prettyPrintIL' (Var Nothing $ withPrefix name)
200− , return $ emit "()"
201− ]
202− match (Indexer _ (Var _ name) val) = mconcat <$> sequence
203− [ prettyPrintIL' val
204− , return $ emit "."
205− , prettyPrintIL' (Var Nothing $ withPrefix name)
206− , return $ emit "()"
207− ]
208− match (Indexer _ prop@StringLiteral{} val@ObjectLiteral{}) = mconcat <$> sequence
209− [ prettyPrintIL' val
210− , return $ emit "["
211− , prettyPrintIL' prop
212− , return $ emit "]"
213− ]
214− match (Indexer _ prop@StringLiteral{} val) = mconcat <$> sequence
215− [ prettyPrintIL' val
216− , return $ emit ".("
217− , return $ emit dictType
218− , return $ emit ")["
219− , prettyPrintIL' prop
220− , return $ emit "]"
221− ]
222− match (Indexer _ index val@ArrayLiteral{}) = mconcat <$> sequence
223− [ prettyPrintIL' val
224− , return $ emit "["
225− , prettyPrintIL' index
226− , return $ emit "]"
227− ]
228− match (Indexer _ index val) = mconcat <$> sequence
229− [ prettyPrintIL' val
230− , return $ emit ".("
231− , return $ emit arrayType
232− , return $ emit ")["
233− , prettyPrintIL' index
234− , return $ emit "]"
235− ]
236− match (InstanceOf _ val ty) = mconcat <$> sequence
237− [ return $ emit "Is("
238− , prettyPrintIL' val
239− , return $ emit ", "
240− , prettyPrintIL' ty
241− , return $ emit ")"
242− ]
243− match (While _ cond sts) = mconcat <$> sequence
244− [ return $ emit "for "
245− , prettyPrintIL' cond
246− , return $ emit " "
247− , prettyPrintIL' sts
248− ]
249− match (For _ ident start end sts) = mconcat <$> sequence
250− [ return $ emit $ "for var " <> ident <> " = "
251− , prettyPrintIL' start
252− , return $ emit $ "; " <> ident <> " < "
253− , prettyPrintIL' end
254− , return $ emit $ "; " <> ident <> "++ "
255− , prettyPrintIL' sts
256− ]
257− match (ForIn _ ident obj sts) = mconcat <$> sequence
258− [ return $ emit $ "for var " <> ident <> " in "
259− , prettyPrintIL' obj
260− , return $ emit " "
261− , prettyPrintIL' sts
262− ]
263− match (IfElse _ (Binary _ EqualTo cond@Binary{} (BooleanLiteral Nothing True)) thens elses) = mconcat <$> sequence
264− [ return $ emit "if "
265− , prettyPrintIL' cond
266− , return $ emit " "
267− , prettyPrintIL' thens
268− , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
269− ]
270− match (IfElse _ (Binary _ EqualTo cond@Binary{} (BooleanLiteral Nothing False)) thens elses) = mconcat <$> sequence
271− [ return $ emit "if !("
272− , prettyPrintIL' cond
273− , return $ emit ") "
274− , prettyPrintIL' thens
275− , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
276− ]
277− match (IfElse _ cond thens elses) = mconcat <$> sequence
278− [ return $ emit "if "
279− , prettyPrintIL' cond
280− , return $ emit " "
281− , prettyPrintIL' thens
282− , maybe (return mempty) (fmap (emit " else " <>) . prettyPrintIL') elses
283− ]
284− match (Return _ value) = mconcat <$> sequence
285− [ return $ emit "return "
286− , prettyPrintIL' value
287− ]
288− match (ReturnNoResult _) = return . emit $ "return " <> undefinedName
289− -- match (Throw _ _) = return mempty
290− match (Throw _ value) = mconcat <$> sequence
291− [ return $ emit "panic("
292− , prettyPrintIL' value
293− , return $ emit ")"
294− ]
295− match (Comment _ com il) = mconcat <$> sequence
296− [ return $ emit "\n"
297− , mconcat <$> forM com comment
298− , prettyPrintIL' il
299− ]
300− match _ = mzero
301−
302− comment :: (Emit gen) => Comment -> StateT PrinterState Maybe gen
303− comment (LineComment com) = fmap mconcat $ sequence $
304− [ currentIndent
305− , return $ emit "//" <> emit com <> emit "\n"
306− ]
307− comment (BlockComment com) = fmap mconcat $ sequence $
308− [ currentIndent
309− , return $ emit "/**\n"
310− ] ++
311− map asLine (T.lines com) ++
312− [ currentIndent
313− , return $ emit " */\n"
314− , currentIndent
315− ]
316− where
317− asLine :: (Emit gen) => Text -> StateT PrinterState Maybe gen
318− asLine s = do
319− i <- currentIndent
320− return $ i <> emit " * " <> (emit . removeComments) s <> emit "\n"
321−
322− removeComments :: Text -> Text
323− removeComments t =
324− case T.stripPrefix "*/" t of
325− Just rest -> removeComments rest
326− Nothing -> case T.uncons t of
327− Just (x, xs) -> x `T.cons` removeComments xs
328− Nothing -> ""
329−
330−unary' :: (Emit gen) => UnaryOperator -> (AST -> Text) -> Operator PrinterState AST gen
331−unary' op mkStr = Wrap match (<>)
332− where
333− match :: (Emit gen) => Pattern PrinterState AST (gen, AST)
334− match = mkPattern match'
335− where
336− match' (Unary _ op' val) | op' == op = Just (emit $ mkStr val, val)
337− match' _ = Nothing
338−
339−unary :: (Emit gen) => UnaryOperator -> Text -> Operator PrinterState AST gen
340−unary op str = unary' op (const str)
341−
342−negateOperator :: (Emit gen) => Operator PrinterState AST gen
343−negateOperator = unary' Negate (\v -> if isNegate v then "- " else "-")
344− where
345− isNegate (Unary _ Negate _) = True
346− isNegate _ = False
347−
348−binary :: (Emit gen) => BinaryOperator -> Text -> Operator PrinterState AST gen
349−binary op str = AssocL match (\v1 v2 -> v1 <> emit (" " <> str <> " ") <> v2)
350− where
351− match :: Pattern PrinterState AST (AST, AST)
352− match = mkPattern match'
353− where
354− match' (Binary _ op' v1 v2) | op' == op = Just (v1, v2)
355− match' _ = Nothing
356−
357−isLiteral :: AST -> Bool
358−isLiteral Function{} = True
359−isLiteral NumericLiteral{} = True
360−isLiteral StringLiteral{} = True
361−isLiteral BooleanLiteral{} = True
362−isLiteral ObjectLiteral{} = True
363−isLiteral ArrayLiteral{} = True
364−isLiteral _ = False
365−
366−isComplexLiteral :: AST -> Bool
367−-- isComplexLiteral Function{} = True
368−isComplexLiteral ObjectLiteral{} = True
369−isComplexLiteral ArrayLiteral{} = True
370−isComplexLiteral _ = False
371−
372−unApp :: AST -> [AST] -> (AST, [AST])
373−unApp (App _ val [arg]) args = unApp val (arg : args)
374−unApp other args = (other, args)
375−
376−prettyStatements :: (Emit gen) => [AST] -> StateT PrinterState Maybe gen
377−prettyStatements sts = do
378− ils <- forM sts prettyPrintIL'
379− indentString <- currentIndent
380− return $ intercalate (emit "\n") $ map (indentString <>) ils
381−
382−-- | Generate a pretty-printed string representing a collection of C++ expressions at the same indentation level
383−prettyPrintILWithSourceMaps :: [AST] -> (Text, [SMap])
384−prettyPrintILWithSourceMaps il =
385− let StrPos (_, s, mp) = (fromMaybe (internalError "Incomplete pattern") . flip evalStateT (PrinterState 0) . prettyStatements) il
386− in (s, mp)
387−
388−prettyPrintIL :: [AST] -> Text
389−prettyPrintIL = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyStatements
390−
391−-- | Generate an indented, pretty-printed string representing a C++ expression
392−prettyPrintIL' :: (Emit gen) => AST -> StateT PrinterState Maybe gen
393−prettyPrintIL' = A.runKleisli $ runPattern matchValue
394− where
395− matchValue :: (Emit gen) => Pattern PrinterState AST gen
396− matchValue = buildPrettyPrinter operators (literals <+> fmap parensPos matchValue)
397− operators :: (Emit gen) => OperatorTable PrinterState AST gen
398− operators =
399− OperatorTable [ [ unary New "?" ]
400− , [ unary Not "!"
401− , unary BitwiseNot "~"
402− , unary Positive "+"
403− , negateOperator ]
404− , [ binary Multiply "*"
405− , binary Divide "/"
406− , binary Modulus "%" ]
407− , [ binary Add "+"
408− , binary Subtract "-" ]
409− , [ binary ShiftLeft "<<"
410− , binary ShiftRight ">>" ]
411− , [ binary LessThan "<"
412− , binary LessThanOrEqualTo "<="
413− , binary GreaterThan ">"
414− , binary GreaterThanOrEqualTo ">=" ]
415− , [ binary EqualTo "=="
416− , binary NotEqualTo "!=" ]
417− , [ binary BitwiseAnd "&" ]
418− , [ binary BitwiseXor "^" ]
419− , [ binary BitwiseOr "|" ]
420− , [ binary And "&&" ]
421− , [ binary Or "||" ]
422− ]
423−
424−prettyPrintIL1 :: AST -> Text
425−prettyPrintIL1 = maybe (internalError "Incomplete pattern") runPlainString . flip evalStateT (PrinterState 0) . prettyPrintIL'
426−
427−stringLiteral :: PSString -> Text
428−stringLiteral pss | Just s <- decodeString pss = stringLiteral' s
429− where
430− stringLiteral' :: Text -> Text
431− stringLiteral' s = "\"" <> T.concatMap encodeChar s <> "\""
432− encodeChar :: Char -> Text
433− encodeChar '\0' = "\\x00"
434− encodeChar '\b' = "\\b"
435− encodeChar '\t' = "\\t"
436− encodeChar '\n' = "\\n"
437− encodeChar '\v' = "\\v"
438− encodeChar '\f' = "\\f"
439− encodeChar '\r' = "\\r"
440− encodeChar '"' = "\\\""
441− encodeChar '\\' = "\\\\"
442− encodeChar c = T.singleton $ c
443−stringLiteral _ = "\"\\uFFFD\""
444−
445−interfaceSource :: Text -> [(Text,Bool)] -> [Ident] -> Text
446−interfaceSource _ _ _ = ""
447−
448−implHeaderSource :: Text -> [Text] -> Text -> Text
449−implHeaderSource mn imports otherPrefix =
450− "// Code generated by psgo. DO NOT EDIT.\n\n" <>
451− "package " <> (if mn == "Main" || mn == "Test_Main" then "main" else mn) <> "\n\n" <>
452− "import . \"" <> runtime <> "\"\n" <>
453− (if mn == "Main" || mn == "Test_Main"
454− then "import _ \"" <> otherPrefix <> "/" <> ffiLoader <> "\"\n"
455− else "\n") <>
456− "import (\n" <>
457− (T.concat $ formatImport <$> imports) <> ")\n\n" <>
458− "type _ = Any\n\n"
459− where
460− formatImport :: Text -> Text
461− formatImport s =
462− "\t\"" <> otherPrefix <> "/" <> modPrefix <> "/" <> moduleRenamer s <> "\"\n"
463− moduleRenamer :: Text -> Text
464− moduleRenamer s
465− | (s', sfx) <- T.breakOn moduleRenamerMarker s,
466− not $ T.null sfx = s'
467− moduleRenamer s = s
468−
469−implFooterSource :: Text -> [Ident] -> Text
470−implFooterSource mn foreigns =
471− "\n\n\n" <>
472− (if null foreigns
473− then ""
474− else ("// Foreign values\n\n" <>
475− "var " <> foreignDict <> " = "<> foreignMod <> "(\"" <> mn <> "\")\n\n" <>
476− (T.concat $ (\foreign' ->
477− let name = moduleIdentToIL foreign' in
478− varDecl <> " " <> initName name <> " Once\n" <>
479− varDecl <> " " <> valueName name <> " " <> anyType <> "\n\n" <>
480− "func " <>
481− withPrefix name <>
482− "() Any { \n" <>
483− " " <> initName name <> ".Do(func() {\n" <>
484− " " <> valueName name <> " = " <>
485− "Get(" <> foreignDict <> ", " <>
486− (stringLiteral . mkString $ runIdent foreign') <> ")\n" <>
487− " })\n" <>
488− " return " <> valueName name <> "\n" <>
489− "}\n\n") <$> foreigns))) <>
490− if mn == "Main" || mn == "Test.Main" then mainSource else "\n"
491− where
492− mainSource :: Text
493− mainSource = "\
494− \func main() {\n\
495− \ Run(Ꞌmain())\n\
496− \}\n\n\
497− \"
498−
499−varDecl :: Text
500−varDecl = "var"
501−
502−renderArg :: Text -> Text -> Text
503−renderArg decl arg = arg <> " " <> decl
504−
505−foreignMod :: Text
506−foreignMod = "Foreign"
507−
508−foreignDict :: Text
509−foreignDict = "foreign"
510−
511−modLabel :: Text
512−modLabel = "purescript-native"
513−
514−modPrefix :: Text
515−modPrefix = modLabel <> "/output"
516−
517−runtime :: Text
518−runtime = "github.com/" <> modLabel <> "/go-runtime"
519−
520−ffiLoader :: Text
521−ffiLoader = modLabel <> "/ffi-loader"
522−
523−initName :: Text -> Text
524−initName s = "ᛌ" <> s <> "_once"
525−
526−valueName :: Text -> Text
527−valueName s = "ᛧ" <> s
src/Main.hsnew file+71
@@ -0,0 +1,71 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Main
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module Main where
16+
17+import PureScript
18+import Data.Maybe (mapMaybe)
19+import Data.List (intercalate)
20+import System.Console.CmdTheLine
21+import Control.Applicative
22+import System.Exit (exitSuccess, exitFailure)
23+import qualified System.IO.UTF8 as U
24+import qualified Data.Map as M
25+
26+compile :: [FilePath] -> Maybe FilePath -> Maybe FilePath -> IO ()
27+compile inputFiles outputFile externsFile = do
28+ input <- fmap concat $ mapM U.readFile inputFiles
29+ let ast = parseDeclarations input
30+ case ast of
31+ Left err -> do
32+ U.print err
33+ exitFailure
34+ Right decls -> do
35+ case check (typeCheckAll decls) of
36+ Left typeError -> do
37+ U.putStrLn typeError
38+ exitFailure
39+ Right (_, env) -> do
40+ let js = intercalate "\n" $ mapMaybe declToJs decls
41+ case outputFile of
42+ Just path -> U.writeFile path js
43+ Nothing -> U.putStrLn js
44+ case externsFile of
45+ Nothing -> return ()
46+ Just filePath -> U.writeFile filePath $ intercalate "\n\n" $ map externToJs $ M.toList $ names env
47+ exitSuccess
48+
49+inputFiles :: Term [FilePath]
50+inputFiles = nonEmpty $ posAny [] $ posInfo
51+ { posDoc = "The input .ps files" }
52+
53+outputFile :: Term (Maybe FilePath)
54+outputFile = value $ opt Nothing $ (optInfo [ "o", "output" ])
55+ { optDoc = "The output .js file" }
56+
57+externsFile :: Term (Maybe FilePath)
58+externsFile = value $ opt Nothing $ (optInfo [ "e", "externs" ])
59+ { optDoc = "The output .e.ps file" }
60+
61+term :: Term (IO ())
62+term = compile <$> inputFiles <*> outputFile <*> externsFile
63+
64+termInfo :: TermInfo
65+termInfo = defTI
66+ { termName = "psc"
67+ , version = "1.0"
68+ , termDoc = "Compiles PureScript to Javascript"
69+ }
70+
71+main = run (term, termInfo)
src/PureScript.hsnew file+31
@@ -0,0 +1,31 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript (
16+ module PureScript.Values,
17+ module PureScript.Types,
18+ module PureScript.Kinds,
19+ module PureScript.Declarations,
20+ module PureScript.Parser,
21+ module PureScript.CodeGen,
22+ module PureScript.TypeChecker
23+) where
24+
25+import PureScript.Values
26+import PureScript.Types
27+import PureScript.Kinds
28+import PureScript.Declarations
29+import PureScript.Parser
30+import PureScript.CodeGen
31+import PureScript.TypeChecker
src/PureScript/CodeGen.hsnew file+355
@@ -0,0 +1,355 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.CodeGen
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+{-# LANGUAGE GADTs, GeneralizedNewtypeDeriving #-}
16+
17+module PureScript.CodeGen (
18+ declToJs,
19+ externToJs
20+) where
21+
22+import Data.Maybe (fromMaybe)
23+import Data.List (nub, intersperse, intercalate)
24+import Data.Function (fix)
25+import Control.Monad.State
26+import Control.Applicative (Applicative(..), Alternative(..))
27+import qualified Control.Category as C
28+import Control.Category ((>>>))
29+import qualified Control.Arrow as A
30+import Control.Arrow ((***))
31+
32+import PureScript.Values
33+import PureScript.Types
34+import PureScript.Declarations
35+
36+-- First Order Patterns
37+
38+newtype Pattern a b = Pattern { runPattern :: A.Kleisli Maybe a b } deriving (C.Category, A.Arrow)
39+
40+pattern :: Pattern a b -> a -> Maybe b
41+pattern = A.runKleisli . runPattern
42+
43+instance Functor (Pattern a) where
44+ fmap f p = Pattern $ A.Kleisli $ fmap f . pattern p
45+
46+instance Applicative (Pattern a) where
47+ pure = Pattern . A.Kleisli . const . pure
48+ f <*> x = Pattern . A.Kleisli $ \a -> pattern f a <*> pattern x a
49+
50+instance Alternative (Pattern a) where
51+ empty = Pattern $ A.Kleisli $ \a -> empty
52+ (Pattern (A.Kleisli p)) <|> (Pattern (A.Kleisli q)) = Pattern $ A.Kleisli $ \a -> p a <|> q a
53+
54+parens :: String -> String
55+parens s = ('(':s) ++ ")"
56+
57+chainl :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r
58+chainl split f p = fix $ \c -> (split >>> (c *** p) >>> A.arr (uncurry f)) <|> p
59+
60+chainr :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r
61+chainr split f p = fix $ \c -> (split >>> (p *** c) >>> A.arr (uncurry f)) <|> p
62+
63+wrap :: Pattern a (s, a) -> (s -> r -> r) -> Pattern a r -> Pattern a r
64+wrap split f p = fix $ \c -> (split >>> (C.id *** c) >>> A.arr (uncurry f)) <|> p
65+
66+split :: Pattern a (s, t) -> (s -> t -> r) -> Pattern a r -> Pattern a r
67+split s f p = (s >>> A.arr (uncurry f)) <|> p
68+
69+data OperatorTable a r = OperatorTable { runOperatorTable :: [Operator a r] }
70+
71+data Operator a r where
72+ AssocL :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r
73+ AssocR :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r
74+ Wrap :: Pattern a (s, a) -> (s -> r -> r) -> Operator a r
75+ Split :: Pattern a (s, t) -> (s -> t -> r) -> Operator a r
76+
77+buildPrettyPrinter :: OperatorTable a r -> Pattern a r -> Pattern a r
78+buildPrettyPrinter table p = foldl (\p' op ->
79+ case op of
80+ AssocL pat g -> chainl pat g p'
81+ AssocR pat g -> chainr pat g p'
82+ Wrap pat g -> wrap pat g p'
83+ Split pat g -> split pat g p'
84+ ) p $ runOperatorTable table
85+
86+-- Variable Name Generation
87+
88+newtype Gen a = Gen { unGen :: State Int a } deriving (Functor, Monad, MonadState Int)
89+
90+runGen :: Gen a -> a
91+runGen = flip evalState 0 . unGen
92+
93+fresh :: Gen String
94+fresh = do
95+ n <- get
96+ modify (+ 1)
97+ return $ "_" ++ show n
98+
99+-- Pretty Printing
100+
101+declToJs :: Declaration -> Maybe String
102+declToJs (ValueDeclaration name val) = Just $ "var " ++ name ++ " = " ++ valueToJs val ++ ";"
103+declToJs (DataDeclaration dcs@(DataConstructors { dataConstructors = ctors })) =
104+ Just $ flip concatMap ctors $ \(ctor, maybeTy) ->
105+ case maybeTy of
106+ Nothing -> "var " ++ ctor ++ " = { ctor: '" ++ ctor ++ "' };"
107+ Just _ -> "var " ++ ctor ++ " = function (value) { return { ctor: '" ++ ctor ++ "', value: value }; };"
108+declToJs _ = Nothing
109+
110+literals :: Pattern Value String
111+literals = Pattern $ A.Kleisli match
112+ where
113+ match (NumericLiteral n) = Just $ either show show n
114+ match (StringLiteral s) = Just $ show s
115+ match (BooleanLiteral True) = Just "true"
116+ match (BooleanLiteral False) = Just "false"
117+ match (ArrayLiteral xs) = Just $ "[" ++ intercalate "," (map valueToJs xs) ++ "]"
118+ match (ObjectLiteral ps) = Just $ "{" ++ intercalate "," (map objectPropertyToJs ps) ++ "}"
119+ match (Constructor name) = Just name
120+ match (Block sts) = Just $ "(function () {" ++ intercalate ";" (map statementToJs sts) ++ "})()"
121+ match (Case value binders) = Just $ "(" ++ runGen (bindersToJs binders) ++ ")(" ++ valueToJs value ++ ")"
122+ where
123+ bindersToJs :: [(Binder, Value)] -> Gen String
124+ bindersToJs binders = do
125+ valName <- fresh
126+ jss <- flip mapM binders $ \(binder, result) -> do
127+ let js = valueToJs result
128+ binderToJs valName ("return " ++ js ++ ";") binder
129+ return $ "function (" ++ valName ++ ") {" ++ concat jss ++ "throw \"Failed pattern match\"; }"
130+ match (Var ident) = Just ident
131+ match _ = Nothing
132+
133+accessor :: Pattern Value (String, Value)
134+accessor = Pattern $ A.Kleisli match
135+ where
136+ match (Accessor prop val) = Just (prop, val)
137+ match _ = Nothing
138+
139+indexer :: Pattern Value (String, Value)
140+indexer = Pattern $ A.Kleisli match
141+ where
142+ match (Indexer index val) = Just (valueToJs index, val)
143+ match _ = Nothing
144+
145+app :: Pattern Value (String, Value)
146+app = Pattern $ A.Kleisli match
147+ where
148+ match (App val args) = Just (intercalate "," (map valueToJs args), val)
149+ match _ = Nothing
150+
151+lam :: Pattern Value ([String], Value)
152+lam = Pattern $ A.Kleisli match
153+ where
154+ match (Abs args val) = Just (args, val)
155+ match _ = Nothing
156+
157+unary :: UnaryOperator -> String -> Operator Value String
158+unary op str = Wrap pattern (++)
159+ where
160+ pattern :: Pattern Value (String, Value)
161+ pattern = Pattern $ A.Kleisli match
162+ where
163+ match (Unary op' val) | op' == op = Just (str, val)
164+ match _ = Nothing
165+
166+binary :: BinaryOperator -> String -> Operator Value String
167+binary op str = AssocR pattern (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
168+ where
169+ pattern :: Pattern Value (Value, Value)
170+ pattern = Pattern $ A.Kleisli match
171+ where
172+ match (Binary op' v1 v2) | op' == op = Just (v1, v2)
173+ match _ = Nothing
174+
175+valueToJs :: Value -> String
176+valueToJs = fromMaybe (error "Incomplete pattern") . pattern matchValue
177+ where
178+ matchValue :: Pattern Value String
179+ matchValue = buildPrettyPrinter operators (literals <|> fmap parens matchValue)
180+ operators :: OperatorTable Value String
181+ operators =
182+ OperatorTable $ [ Wrap accessor $ \prop val -> val ++ "." ++ prop
183+ , Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]"
184+ , Wrap app $ \args val -> val ++ "(" ++ args ++ ")"
185+ , Split lam $ \args val -> "function (" ++ intercalate "," args ++ ") { return " ++ valueToJs val ++ "; }"
186+ , binary LessThan "<"
187+ , binary LessThanOrEqualTo "<="
188+ , binary GreaterThan ">"
189+ , binary GreaterThanOrEqualTo ">="
190+ , unary Not "!"
191+ , unary BitwiseNot "~"
192+ , unary Negate "-"
193+ , binary Multiply "*"
194+ , binary Divide "/"
195+ , binary Modulus "%"
196+ , binary Concat "++"
197+ , binary Add "+"
198+ , binary Subtract "-"
199+ , binary ShiftLeft "<<"
200+ , binary ShiftRight ">>"
201+ , binary ZeroFillShiftRight ">>>"
202+ , binary EqualTo "==="
203+ , binary NotEqualTo "!=="
204+ , binary BitwiseAnd "&"
205+ , binary BitwiseXor "^"
206+ , binary BitwiseOr "|"
207+ , binary And "&&"
208+ , binary Or "||"
209+ ]
210+
211+unaryOperatorString :: UnaryOperator -> String
212+unaryOperatorString Negate = "-"
213+unaryOperatorString Not = "!"
214+unaryOperatorString BitwiseNot = "~"
215+
216+binaryOperatorString :: BinaryOperator -> String
217+binaryOperatorString Add = "+"
218+binaryOperatorString Subtract = "-"
219+binaryOperatorString Multiply = "*"
220+binaryOperatorString Divide = "/"
221+binaryOperatorString Modulus = "%"
222+binaryOperatorString LessThan = "<"
223+binaryOperatorString LessThanOrEqualTo = "<="
224+binaryOperatorString GreaterThan = ">"
225+binaryOperatorString GreaterThanOrEqualTo = ">="
226+binaryOperatorString BitwiseAnd = "&"
227+binaryOperatorString BitwiseOr = "|"
228+binaryOperatorString BitwiseXor = "^"
229+binaryOperatorString ShiftLeft = "<<"
230+binaryOperatorString ShiftRight = ">>"
231+binaryOperatorString ZeroFillShiftRight = ">>>"
232+binaryOperatorString EqualTo = "==="
233+binaryOperatorString NotEqualTo = "!=="
234+binaryOperatorString And = "&&"
235+binaryOperatorString Or = "||"
236+binaryOperatorString Concat = "+"
237+
238+binderToJs :: String -> String -> Binder -> Gen String
239+binderToJs varName done (StringBinder str) =
240+ return $ "if (" ++ varName ++ " === \"" ++ str ++ "\") {" ++ done ++ " }"
241+binderToJs varName done (NumberBinder num) =
242+ return $ "if (" ++ varName ++ " === \"" ++ either show show num ++ "\") {" ++ done ++ " }"
243+binderToJs varName done (BooleanBinder True) =
244+ return $ "if (" ++ varName ++ ") {" ++ done ++ " }"
245+binderToJs varName done (BooleanBinder False) =
246+ return $ "if (!" ++ varName ++ ") {" ++ done ++ " }"
247+binderToJs varName done (VarBinder s) =
248+ return $ "var " ++ s ++ " = " ++ varName ++ "; " ++ done
249+binderToJs varName done (NullaryBinder ctor) =
250+ return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ done ++ " }"
251+binderToJs varName done (UnaryBinder ctor b) = do
252+ value <- fresh
253+ js <- binderToJs value done b
254+ return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ "var " ++ value ++ " = " ++ varName ++ ".value; " ++ js ++ " }"
255+binderToJs varName done (ObjectBinder bs) = go done bs
256+ where
257+ go done [] = return done
258+ go done ((prop, binder):bs) = do
259+ propVar <- fresh
260+ done' <- go done bs
261+ js <- binderToJs propVar done' binder
262+ return $ "var " ++ propVar ++ " = " ++ varName ++ "." ++ prop ++ ";" ++ js
263+binderToJs done varName (ArrayBinder bs rest) = do
264+ js <- go done rest 0 bs
265+ return $ "if (" ++ varName ++ ".length " ++ cmp ++ " " ++ show (length bs) ++ ") { " ++ js ++ " }"
266+ where
267+ cmp = maybe "===" (const ">=") rest
268+ go done Nothing _ [] = return done
269+ go done (Just binder) index [] = do
270+ restVar <- fresh
271+ js <- binderToJs restVar done binder
272+ return $ "var " ++ restVar ++ " = " ++ varName ++ ".slice(" ++ show index ++ "); " ++ js
273+ go done rest index (binder:bs) = do
274+ elVar <- fresh
275+ done' <- go done rest (index + 1) bs
276+ js <- binderToJs elVar done' binder
277+ return $ "var " ++ elVar ++ " = " ++ varName ++ "[" ++ show index ++ "]; " ++ js
278+
279+objectPropertyToJs :: (String, Value) -> String
280+objectPropertyToJs (key, value) = key ++ ":" ++ valueToJs value
281+
282+statementToJs :: Statement -> String
283+statementToJs (VariableIntroduction name value) = "var " ++ name ++ " = " ++ valueToJs value
284+statementToJs (Assignment target value) = assignmentTargetToJs target ++ " = " ++ valueToJs value
285+statementToJs (While cond sts) = "while ("
286+ ++ valueToJs cond ++ ") {"
287+ ++ intercalate ";" (map statementToJs sts) ++ "}"
288+statementToJs (For (init, cond, done) sts) = "for (" ++
289+ statementToJs init
290+ ++ "; " ++ valueToJs cond
291+ ++ "; " ++ statementToJs done
292+ ++ ") {" ++ intercalate ";" (map statementToJs sts) ++ "}"
293+statementToJs (IfThenElse cond thens elses) = "if ("
294+ ++ valueToJs cond ++ ") {"
295+ ++ intercalate ";" (map statementToJs thens) ++ "}"
296+ ++ flip (maybe "") elses (\sts ->
297+ " else {" ++ intercalate ";" (map statementToJs sts) ++ "}")
298+statementToJs (Return value) = "return " ++ valueToJs value
299+
300+assignmentTargetToJs :: AssignmentTarget -> String
301+assignmentTargetToJs (AssignVariable var) = var
302+assignmentTargetToJs (AssignArrayIndex index tgt) = assignmentTargetToJs tgt ++ "[" ++ valueToJs index ++ "]"
303+assignmentTargetToJs (AssignObjectProperty prop tgt) = assignmentTargetToJs tgt ++ "." ++ prop
304+
305+-- Externs
306+
307+typeLiterals :: Pattern Type String
308+typeLiterals = Pattern $ A.Kleisli match
309+ where
310+ match Number = Just "Number"
311+ match String = Just "String"
312+ match Boolean = Just "Boolean"
313+ match (Array ty) = Just $ "[" ++ typeToPs ty ++ "]"
314+ match (Object row) = Just $ "{ " ++ rowToPs row ++ " }"
315+ match (TypeVar var) = Just var
316+ match (TypeConstructor ctor) = Just ctor
317+ match _ = Nothing
318+
319+rowToPs :: Row -> String
320+rowToPs = (\(tys, tail) -> intercalate "; " (map (uncurry nameAndTypeToPs) tys) ++ tailToPs tail) . toList
321+ where
322+ nameAndTypeToPs :: String -> Type -> String
323+ nameAndTypeToPs name ty = name ++ " :: " ++ typeToPs ty
324+ tailToPs :: Row -> String
325+ tailToPs REmpty = ""
326+ tailToPs (RowVar var) = " | " ++ var
327+ toList :: Row -> ([(String, Type)], Row)
328+ toList (RCons name ty row) = let (tys, rest) = toList row
329+ in ((name, ty):tys, rest)
330+ toList r = ([], r)
331+
332+typeApp :: Pattern Type (Type, Type)
333+typeApp = Pattern $ A.Kleisli match
334+ where
335+ match (TypeApp f x) = Just (f, x)
336+ match _ = Nothing
337+
338+function :: Pattern Type ([Type], Type)
339+function = Pattern $ A.Kleisli match
340+ where
341+ match (Function args ret) = Just (args, ret)
342+ match _ = Nothing
343+
344+typeToPs :: Type -> String
345+typeToPs = fromMaybe (error "Incomplete pattern") . pattern matchType
346+ where
347+ matchType :: Pattern Type String
348+ matchType = buildPrettyPrinter operators (typeLiterals <|> fmap parens matchType)
349+ operators :: OperatorTable Type String
350+ operators =
351+ OperatorTable $ [ AssocL typeApp $ \f x -> f ++ " " ++ x
352+ , Split function $ \args ret -> "(" ++ intercalate "," (map typeToPs args) ++ ") -> " ++ typeToPs ret ]
353+
354+externToJs :: (String, Type) -> String
355+externToJs (name, ty) = "extern " ++ name ++ " :: " ++ typeToPs ty
src/PureScript/Declarations.hsnew file+33
@@ -0,0 +1,33 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.Declarations
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.Declarations (
16+ Declaration (..),
17+ DataConstructors (..)
18+) where
19+
20+import PureScript.Values
21+import PureScript.Types
22+
23+data Declaration
24+ = DataDeclaration DataConstructors
25+ | TypeDeclaration String Type
26+ | ValueDeclaration String Value
27+ | ExternDeclaration String Type deriving Show
28+
29+data DataConstructors = DataConstructors
30+ { typeConstructorName :: String
31+ , typeArguments :: [String]
32+ , dataConstructors :: [(String, Maybe Type)]
33+ } deriving Show
src/PureScript/Kinds.hsnew file+23
@@ -0,0 +1,23 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.Kinds
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.Kinds (
16+ Kind (..)
17+) where
18+
19+data Kind
20+ = KUnknown Int
21+ | Star
22+ | Row
23+ | FunKind Kind Kind deriving (Show, Eq)
src/PureScript/Parser.hsnew file+24
@@ -0,0 +1,24 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.Parser
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.Parser (
16+ module PureScript.Parser.Types,
17+ module PureScript.Parser.Values,
18+ module PureScript.Parser.Declarations
19+) where
20+
21+import PureScript.Parser.Types
22+import PureScript.Parser.Values
23+import PureScript.Parser.Declarations
24+
src/PureScript/Parser/Common.hsnew file+73
@@ -0,0 +1,73 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.Parser.Common
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.Parser.Common where
16+
17+import Control.Applicative
18+import qualified Text.Parsec as P
19+import qualified Text.Parsec.Token as PT
20+import qualified Text.Parsec.Language as PL
21+
22+langDef = PL.haskellStyle
23+ { PT.identStart = P.lower <|> P.char '_'
24+ , PT.reservedNames = [ "case"
25+ , "data"
26+ , "var"
27+ , "while"
28+ , "for"
29+ , "if"
30+ , "then"
31+ , "else"
32+ , "return"
33+ , "true"
34+ , "false"
35+ , "extern" ]
36+ }
37+
38+tokenParser = PT.makeTokenParser langDef
39+lexeme = PT.lexeme tokenParser
40+identifier = PT.identifier tokenParser
41+reserved = PT.reserved tokenParser
42+operator = PT.operator tokenParser
43+stringLiteral = PT.stringLiteral tokenParser
44+natural = PT.natural tokenParser
45+naturalOrFloat = PT.naturalOrFloat tokenParser
46+whiteSpace = PT.whiteSpace tokenParser
47+parens = PT.parens tokenParser
48+braces = PT.braces tokenParser
49+angles = PT.angles tokenParser
50+brackets = PT.brackets tokenParser
51+squares = PT.squares tokenParser
52+semi = PT.semi tokenParser
53+comma = PT.comma tokenParser
54+colon = PT.colon tokenParser
55+dot = PT.dot tokenParser
56+semiSep = PT.semiSep tokenParser
57+semiSep1 = PT.semiSep1 tokenParser
58+commaSep = PT.commaSep tokenParser
59+commaSep1 = PT.commaSep1 tokenParser
60+
61+properName :: P.Parsec String u String
62+properName = lexeme $ P.try properName'
63+ where
64+ properName' = (:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name"
65+
66+augment :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
67+augment p q f = (flip $ maybe id $ flip f) <$> p <*> P.optionMaybe q
68+
69+fold :: P.Stream s m t => P.ParsecT s u m a -> P.ParsecT s u m b -> (a -> b -> a) -> P.ParsecT s u m a
70+fold first more combine = do
71+ a <- first
72+ bs <- P.many more
73+ return $ foldl combine a bs
src/PureScript/Parser/Declarations.hsnew file+63
@@ -0,0 +1,63 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.Parser.Declarations
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.Parser.Declarations (
16+ parseDeclaration,
17+ parseDeclarations
18+) where
19+
20+import Data.Char
21+import Data.List
22+import Data.Function
23+import Control.Applicative
24+import qualified Text.Parsec as P
25+import Control.Arrow (Arrow(..))
26+
27+import PureScript.Values
28+import PureScript.Types
29+import PureScript.Parser.Common
30+import PureScript.Declarations
31+import PureScript.Parser.Values
32+import PureScript.Parser.Types
33+
34+parseDataDeclaration :: P.Parsec String () Declaration
35+parseDataDeclaration = do
36+ reserved "data"
37+ name <- properName
38+ tyArgs <- many identifier
39+ lexeme $ P.char '='
40+ ctors <- P.sepBy1 ((,) <$> properName <*> P.optionMaybe parseType) (lexeme $ P.char '|')
41+ return $ DataDeclaration $ DataConstructors name tyArgs ctors
42+
43+parseTypeDeclaration :: P.Parsec String () Declaration
44+parseTypeDeclaration = TypeDeclaration <$> identifier <*> (lexeme (P.string "::") *> parseType)
45+
46+parseValueDeclaration :: P.Parsec String () Declaration
47+parseValueDeclaration = ValueDeclaration <$> identifier <*> (lexeme (P.char '=') *> parseValue)
48+
49+parseExternDeclaration :: P.Parsec String () Declaration
50+parseExternDeclaration = ExternDeclaration <$> (reserved "extern" *> (identifier <|> properName)) <*> (lexeme (P.string "::") *> parseType)
51+
52+parseDeclaration :: P.Parsec String () Declaration
53+parseDeclaration = P.choice $ map P.try
54+ [ parseDataDeclaration
55+ , parseTypeDeclaration
56+ , parseValueDeclaration
57+ , parseExternDeclaration ]
58+
59+parseDeclarations :: String -> Either P.ParseError [Declaration]
60+parseDeclarations = mapM (P.parse (parseDeclaration <* whiteSpace <* P.eof) "Declaration") . splitFileIntoDeclarations
61+
62+splitFileIntoDeclarations :: String -> [String]
63+splitFileIntoDeclarations = map unlines . filter (not . all isSpace . head) . groupBy ((==) `on` (all isSpace)) . lines
src/PureScript/Parser/Types.hsnew file+80
@@ -0,0 +1,80 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.Parser.Types
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.Parser.Types (
16+ parseType,
17+ parseRow
18+) where
19+
20+import PureScript.Types
21+import PureScript.Parser.Common
22+import Control.Applicative
23+import qualified Text.Parsec as P
24+import Control.Arrow (Arrow(..))
25+
26+parseNumber :: P.Parsec String () Type
27+parseNumber = const Number <$> P.string "Number"
28+
29+parseString :: P.Parsec String () Type
30+parseString = const String <$> P.string "String"
31+
32+parseBoolean :: P.Parsec String () Type
33+parseBoolean = const Boolean <$> P.string "Boolean"
34+
35+parseArray :: P.Parsec String () Type
36+parseArray = squares $ Array <$> parseType
37+
38+parseObject :: P.Parsec String () Type
39+parseObject = braces $ Object <$> parseRow
40+
41+parseFunction :: P.Parsec String () Type
42+parseFunction = do
43+ args <- lexeme $ parens $ commaSep parseType
44+ lexeme $ P.string "->"
45+ resultType <- parseType
46+ return $ Function args resultType
47+
48+parseTypeVariable :: P.Parsec String () Type
49+parseTypeVariable = TypeVar <$> identifier
50+
51+parseTypeConstructor :: P.Parsec String () Type
52+parseTypeConstructor = TypeConstructor <$> properName
53+
54+parseTypeAtom :: P.Parsec String () Type
55+parseTypeAtom = P.choice $ map P.try
56+ [ parseNumber
57+ , parseString
58+ , parseBoolean
59+ , parseArray
60+ , parseObject
61+ , parseFunction
62+ , parseTypeVariable
63+ , parseTypeConstructor
64+ , parens parseType ]
65+
66+parseType :: P.Parsec String () Type
67+parseType = fold (lexeme parseTypeAtom) (lexeme parseTypeAtom) TypeApp
68+
69+parseNameAndType :: P.Parsec String () (String, Type)
70+parseNameAndType = (,) <$> (identifier <* lexeme (P.string "::")) <*> parseType
71+
72+parseRowEnding :: P.Parsec String () Row
73+parseRowEnding = P.option REmpty (RowVar <$> (lexeme (P.char '|') *> identifier))
74+
75+parseRow :: P.Parsec String () Row
76+parseRow = fromList <$> semiSep parseNameAndType <*> parseRowEnding
77+ where
78+ fromList :: [(String, Type)] -> Row -> Row
79+ fromList [] r = r
80+ fromList ((name, t):ts) r = RCons name t (fromList ts r)
src/PureScript/Parser/Values.hsnew file+222
@@ -0,0 +1,222 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.Parser.Values
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.Parser.Values (
16+ parseValue,
17+ parseBinder
18+) where
19+
20+import PureScript.Values
21+import qualified PureScript.Parser.Common as C
22+import Control.Applicative
23+import qualified Text.Parsec as P
24+import Text.Parsec.Expr
25+import Control.Monad
26+import Control.Arrow (Arrow(..))
27+import PureScript.Parser.Types
28+import PureScript.Types
29+
30+booleanLiteral :: P.Parsec String () Bool
31+booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)
32+
33+parseNumericLiteral :: P.Parsec String () Value
34+parseNumericLiteral = NumericLiteral <$> C.naturalOrFloat
35+
36+parseStringLiteral :: P.Parsec String () Value
37+parseStringLiteral = StringLiteral <$> C.stringLiteral
38+
39+parseBooleanLiteral :: P.Parsec String () Value
40+parseBooleanLiteral = BooleanLiteral <$> booleanLiteral
41+
42+parseArrayLiteral :: P.Parsec String () Value
43+parseArrayLiteral = ArrayLiteral <$> (C.squares $ C.commaSep parseValue)
44+
45+parseObjectLiteral :: P.Parsec String () Value
46+parseObjectLiteral = ObjectLiteral <$> (C.braces $ C.commaSep parseIdentifierAndValue)
47+
48+parseIdentifierAndValue :: P.Parsec String () (String, Value)
49+parseIdentifierAndValue = do
50+ name <- C.lexeme C.identifier
51+ C.colon
52+ value <- parseValue
53+ return (name, value)
54+
55+parseAbs :: P.Parsec String () Value
56+parseAbs = do
57+ C.lexeme $ P.char '\\'
58+ args <- C.commaSep C.identifier
59+ C.lexeme $ P.string "->"
60+ value <- parseValue
61+ return $ Abs args value
62+
63+parseApp :: P.Parsec String () Value
64+parseApp = App <$> parseValue
65+ <*> (C.parens $ C.commaSep parseValue)
66+
67+parseVar :: P.Parsec String () Value
68+parseVar = Var <$> (C.identifier <|> C.properName)
69+
70+parseCase :: P.Parsec String () Value
71+parseCase = Case <$> P.between (C.reserved "case") (C.reserved "of") parseValue
72+ <*> C.braces (C.semiSep parseCaseAlternative)
73+
74+parseCaseAlternative :: P.Parsec String () (Binder, Value)
75+parseCaseAlternative = (,) <$> (parseBinder <* C.lexeme (P.string "->")) <*> parseValue
76+
77+parseBlock :: P.Parsec String () Value
78+parseBlock = Block <$> (C.braces $ P.many (parseStatement True))
79+
80+parseValueAtom :: P.Parsec String () Value
81+parseValueAtom = P.choice $ map P.try
82+ [ parseNumericLiteral
83+ , parseStringLiteral
84+ , parseBooleanLiteral
85+ , parseArrayLiteral
86+ , parseObjectLiteral
87+ , parseAbs
88+ , parseVar
89+ , parseBlock
90+ , parseCase
91+ , C.parens parseValue ]
92+
93+parseValue :: P.Parsec String () Value
94+parseValue = buildExpressionParser operators $ C.fold (C.lexeme typedValue) (C.lexeme funArgs) App
95+ where
96+ typedValue = C.augment parseValueAtom parseTypeAnnotation TypedValue
97+ funArgs = C.parens $ C.commaSep parseValue
98+ parseTypeAnnotation = C.lexeme (P.string "::") *> parseType
99+ operators = [ [ Postfix $ Accessor <$> (C.dot *> C.identifier)
100+ , Postfix $ Indexer <$> C.squares parseValue ]
101+ , [ Prefix $ C.lexeme (P.char '!') >> return (Unary Not)
102+ , Prefix $ C.lexeme (P.char '~') >> return (Unary BitwiseNot)
103+ , Prefix $ C.lexeme (P.char '-') >> return (Unary Negate) ]
104+ , [ Infix (C.lexeme (P.try (P.string "<=")) >> return (Binary LessThanOrEqualTo)) AssocRight
105+ , Infix (C.lexeme (P.try (P.string ">=")) >> return (Binary GreaterThanOrEqualTo)) AssocRight
106+ , Infix (C.lexeme (P.try (P.char '<' <* P.notFollowedBy (P.char '<'))) >> return (Binary LessThan)) AssocRight ]
107+ , [ Infix (C.lexeme (P.try (P.char '>' <* P.notFollowedBy (P.char '>'))) >> return (Binary GreaterThan)) AssocRight
108+ , Infix (C.lexeme (P.char '/') >> return (Binary Divide)) AssocRight
109+ , Infix (C.lexeme (P.char '%') >> return (Binary Modulus)) AssocRight ]
110+ , [ Infix (C.lexeme (P.try (P.string "++")) >> return (Binary Concat)) AssocRight
111+ , Infix (C.lexeme (P.char '+') >> return (Binary Add)) AssocRight
112+ , Infix (C.lexeme (P.char '-') >> return (Binary Subtract)) AssocRight ]
113+ , [ Infix (C.lexeme (P.string "<<") >> return (Binary ShiftLeft)) AssocRight
114+ , Infix (C.lexeme (P.try (P.string ">>>")) >> return (Binary ZeroFillShiftRight)) AssocRight
115+ , Infix (C.lexeme (P.string ">>") >> return (Binary ShiftRight)) AssocRight ]
116+ , [ Infix (C.lexeme (P.string "==") >> return (Binary EqualTo)) AssocRight
117+ , Infix (C.lexeme (P.try (P.string "!=")) >> return (Binary NotEqualTo)) AssocRight ]
118+ , [ Infix (C.lexeme (P.try (P.char '&' <* P.notFollowedBy (P.char '&'))) >> return (Binary BitwiseAnd)) AssocRight ]
119+ , [ Infix (C.lexeme (P.char '^') >> return (Binary BitwiseXor)) AssocRight ]
120+ , [ Infix (C.lexeme (P.try (P.char '|' <* P.notFollowedBy (P.char '|'))) >> return (Binary BitwiseOr)) AssocRight ]
121+ , [ Infix (C.lexeme (P.string "&&") >> return (Binary And)) AssocRight ]
122+ , [ Infix (C.lexeme (P.string "||") >> return (Binary Or)) AssocRight ]
123+ ]
124+
125+parseVariableIntroduction :: Bool -> P.Parsec String () Statement
126+parseVariableIntroduction requireSemi = do
127+ C.reserved "var"
128+ name <- C.identifier
129+ C.lexeme $ P.char '='
130+ value <- parseValue
131+ when requireSemi (void C.semi)
132+ return $ VariableIntroduction name value
133+
134+parseAssignment :: Bool -> P.Parsec String () (Statement)
135+parseAssignment requireSemi = do
136+ tgt <- parseAssignmentTarget
137+ C.lexeme $ P.char '='
138+ value <- parseValue
139+ when requireSemi (void C.semi)
140+ return $ Assignment tgt value
141+
142+parseManyStatements :: P.Parsec String () [Statement]
143+parseManyStatements = C.braces $ P.many (parseStatement True)
144+
145+parseWhile :: P.Parsec String () Statement
146+parseWhile = While <$> (C.reserved "while" *> C.parens parseValue)
147+ <*> parseManyStatements
148+
149+parseFor :: P.Parsec String () Statement
150+parseFor = For <$> (C.reserved "for" *> C.parens forIntro)
151+ <*> parseManyStatements
152+ where
153+ forIntro = (,,) <$> parseStatement False
154+ <*> (C.semi *> parseValue)
155+ <*> (C.semi *> parseStatement False)
156+
157+parseIfThenElse :: P.Parsec String () Statement
158+parseIfThenElse = IfThenElse
159+ <$> (C.reserved "if" *> C.parens parseValue)
160+ <*> parseManyStatements
161+ <*> P.optionMaybe (C.reserved "else" *> parseManyStatements)
162+
163+parseReturn :: Bool -> P.Parsec String () Statement
164+parseReturn requireSemi = Return <$> (C.reserved "return" *> parseValue <* when requireSemi (void C.semi))
165+
166+parseStatement :: Bool -> P.Parsec String () Statement
167+parseStatement requireSemi = P.choice $ map P.try
168+ [ parseVariableIntroduction requireSemi
169+ , parseAssignment requireSemi
170+ , parseWhile
171+ , parseFor
172+ , parseIfThenElse
173+ , parseReturn requireSemi ]
174+
175+parseStringBinder :: P.Parsec String () Binder
176+parseStringBinder = StringBinder <$> C.stringLiteral
177+
178+parseBooleanBinder :: P.Parsec String () Binder
179+parseBooleanBinder = BooleanBinder <$> booleanLiteral
180+
181+parseNumberBinder :: P.Parsec String () Binder
182+parseNumberBinder = NumberBinder <$> C.naturalOrFloat
183+
184+parseVarBinder :: P.Parsec String () Binder
185+parseVarBinder = VarBinder <$> C.lexeme C.identifier
186+
187+parseNullaryBinder :: P.Parsec String () Binder
188+parseNullaryBinder = NullaryBinder <$> C.lexeme C.properName
189+
190+parseUnaryBinder :: P.Parsec String () Binder
191+parseUnaryBinder = UnaryBinder <$> C.lexeme C.properName <*> parseBinder
192+
193+parseObjectBinder :: P.Parsec String () Binder
194+parseObjectBinder = ObjectBinder <$> C.braces (C.commaSep parseIdentifierAndBinder)
195+
196+parseArrayBinder :: P.Parsec String () Binder
197+parseArrayBinder = C.squares $ ArrayBinder <$> (C.commaSep parseBinder) <*> P.optionMaybe (C.colon *> parseBinder)
198+
199+parseIdentifierAndBinder :: P.Parsec String () (String, Binder)
200+parseIdentifierAndBinder = do
201+ name <- C.lexeme C.identifier
202+ C.lexeme $ P.char '='
203+ binder <- parseBinder
204+ return (name, binder)
205+
206+parseBinder :: P.Parsec String () Binder
207+parseBinder = P.choice $ map P.try
208+ [ parseStringBinder
209+ , parseBooleanBinder
210+ , parseNumberBinder
211+ , parseVarBinder
212+ , parseUnaryBinder
213+ , parseNullaryBinder
214+ , parseObjectBinder
215+ , parseArrayBinder
216+ , C.parens parseBinder ]
217+
218+parseAssignmentTarget :: P.Parsec String () AssignmentTarget
219+parseAssignmentTarget = buildExpressionParser operators (AssignVariable <$> C.identifier)
220+ where
221+ operators = [ [ Postfix $ AssignArrayIndex <$> C.squares parseValue
222+ , Postfix $ AssignObjectProperty <$> (C.dot *> C.identifier) ] ]
src/PureScript/TypeChecker.hsnew file+80
@@ -0,0 +1,80 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.TypeChecker
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances #-}
16+
17+module PureScript.TypeChecker (
18+ module PureScript.TypeChecker.Monad,
19+ module PureScript.TypeChecker.Kinds,
20+ module PureScript.TypeChecker.Types,
21+ typeCheckAll,
22+) where
23+
24+import PureScript.TypeChecker.Monad
25+import PureScript.TypeChecker.Kinds
26+import PureScript.TypeChecker.Types
27+
28+import Data.List
29+import Data.Maybe
30+import Data.Function
31+
32+import PureScript.Values
33+import PureScript.Types
34+import PureScript.Kinds
35+import PureScript.Declarations
36+
37+import Control.Monad.State
38+import Control.Monad.Error
39+
40+import qualified Data.Map as M
41+
42+typeCheckAll :: [Declaration] -> Check ()
43+typeCheckAll [] = return ()
44+typeCheckAll (DataDeclaration dcs@(DataConstructors
45+ { typeConstructorName = name
46+ , typeArguments = args
47+ , dataConstructors = ctors
48+ }) : rest) = do
49+ rethrow (("Error in type constructor " ++ name ++ ": ") ++) $ do
50+ env <- getEnv
51+ guardWith (name ++ " is already defined") $ not $ M.member name (types env)
52+ ctorKind <- kindsOf name args (catMaybes $ map snd ctors)
53+ putEnv $ env { types = M.insert name ctorKind (types env) }
54+ flip mapM_ ctors $ \(dctor, maybeTy) ->
55+ rethrow (("Error in data constructor " ++ name ++ ": ") ++) $ do
56+ env' <- getEnv
57+ guardWith (dctor ++ " is already defined") $ not $ flip M.member (names env') dctor
58+ let retTy = foldl TypeApp (TypeConstructor name) (map TypeVar args)
59+ let dctorTy = maybe retTy (\ty -> Function [ty] retTy) maybeTy
60+ putEnv $ env' { names = M.insert dctor dctorTy (names env') }
61+ typeCheckAll rest
62+typeCheckAll (TypeDeclaration name ty : ValueDeclaration name' val : rest) | name == name' =
63+ typeCheckAll (ValueDeclaration name (TypedValue val ty) : rest)
64+typeCheckAll (TypeDeclaration name _ : _) = throwError $ "Orphan type declaration for " ++ name
65+typeCheckAll (ValueDeclaration name val : rest) = do
66+ rethrow (("Error in declaration " ++ name ++ ": ") ++) $ do
67+ env <- getEnv
68+ case M.lookup name (names env) of
69+ Just ty -> throwError $ name ++ " is already defined"
70+ Nothing -> do
71+ ty <- typeOf name val
72+ putEnv (env { names = M.insert name ty (names env) })
73+ typeCheckAll rest
74+typeCheckAll (ExternDeclaration name ty : rest) = do
75+ rethrow (("Error in extern declaration " ++ name ++ ": ") ++) $ do
76+ env <- getEnv
77+ case M.lookup name (names env) of
78+ Just _ -> throwError $ name ++ " is already defined"
79+ Nothing -> putEnv (env { names = M.insert name ty (names env) })
80+ typeCheckAll rest
src/PureScript/TypeChecker/Kinds.hsnew file+160
@@ -0,0 +1,160 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.TypeChecker.Kinds
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.TypeChecker.Kinds (
16+ KindConstraint(..),
17+ KindSolution(..),
18+ kindsOf
19+) where
20+
21+import Data.List
22+import Data.Function
23+
24+import PureScript.Types
25+import PureScript.Kinds
26+import PureScript.Declarations
27+import PureScript.TypeChecker.Monad
28+
29+import Control.Monad.State
30+import Control.Monad.Error
31+
32+import Control.Applicative
33+import Control.Arrow (Kleisli(..), (***))
34+import qualified Control.Category as C
35+
36+import qualified Data.Map as M
37+
38+data KindConstraint = KindConstraint Int Kind
39+
40+instance Show KindConstraint where
41+ show (KindConstraint n k) = show n ++ " = " ++ show k
42+
43+newtype KindSolution = KindSolution { runKindSolution :: Int -> Kind }
44+
45+emptyKindSolution :: KindSolution
46+emptyKindSolution = KindSolution KUnknown
47+
48+kindsOf :: String -> [String] -> [Type] -> Check Kind
49+kindsOf name args ts = do
50+ tyCon <- fresh
51+ nargs <- replicateM (length args) fresh
52+ (cs, ns, m) <- kindConstraintsAll (M.insert name tyCon $ M.fromList (zipWith (,) args nargs)) ts
53+ let extraConstraints = KindConstraint tyCon (foldr FunKind Star (map KUnknown nargs)) : map (flip KindConstraint Star) ns
54+ solution <- solveKindConstraints (extraConstraints ++ cs) emptyKindSolution
55+ return $ starIfUnknown $ runKindSolution solution tyCon
56+
57+starIfUnknown :: Kind -> Kind
58+starIfUnknown (KUnknown _) = Star
59+starIfUnknown (FunKind k1 k2) = FunKind (starIfUnknown k1) (starIfUnknown k2)
60+starIfUnknown k = k
61+
62+kindConstraintsAll :: M.Map String Int -> [Type] -> Check ([KindConstraint], [Int], M.Map String Int)
63+kindConstraintsAll m [] = return ([], [], m)
64+kindConstraintsAll m (t:ts) = do
65+ (cs, n1, m') <- kindConstraints m t
66+ (cs', ns, m'') <- kindConstraintsAll m' ts
67+ return ((KindConstraint n1 Star) : cs ++ cs', n1:ns, m'')
68+
69+kindConstraints :: M.Map String Int -> Type -> Check ([KindConstraint], Int, M.Map String Int)
70+kindConstraints m (Array t) = do
71+ me <- fresh
72+ (cs, n1, m') <- kindConstraints m t
73+ return ((KindConstraint n1 Star) : (KindConstraint me Star) : cs, me, m')
74+kindConstraints m (Object row) = do
75+ me <- fresh
76+ (cs, row, m') <- kindConstraintsForRow m row
77+ return ((KindConstraint me Star) : (KindConstraint row Row) : cs, me, m')
78+kindConstraints m (Function args ret) = do
79+ me <- fresh
80+ (cs, ns, m') <- kindConstraintsAll m args
81+ (cs', retN, m'') <- kindConstraints m' ret
82+ return ((KindConstraint retN Star) : (KindConstraint me Star) : (map (flip KindConstraint Star) ns) ++ cs, me, m'')
83+kindConstraints m (TypeVar v) = do
84+ me <- case M.lookup v m of
85+ Just u -> return u
86+ Nothing -> fresh
87+ return ([], me, M.insert v me m)
88+kindConstraints m (TypeConstructor v) = do
89+ env <- getEnv
90+ me <- fresh
91+ case M.lookup v m of
92+ Nothing -> case M.lookup v (types env) of
93+ Nothing -> throwError $ "Unknown type constructor '" ++ v ++ "'"
94+ Just kind -> return ([KindConstraint me kind], me, m)
95+ Just u -> do
96+ return ([KindConstraint me (KUnknown u)], me, m)
97+kindConstraints m (TypeApp t1 t2) = do
98+ me <- fresh
99+ (cs1, n1, m1) <- kindConstraints m t1
100+ (cs2, n2, m2) <- kindConstraints m1 t2
101+ return ((KindConstraint n1 (FunKind (KUnknown n2) (KUnknown me))) : cs1 ++ cs2, me, m2)
102+kindConstraints m _ = do
103+ me <- fresh
104+ return ([KindConstraint me Star], me, m)
105+
106+kindConstraintsForRow :: M.Map String Int -> Row -> Check ([KindConstraint], Int, M.Map String Int)
107+kindConstraintsForRow m (RowVar v) = do
108+ me <- case M.lookup v m of
109+ Just u -> return u
110+ Nothing -> fresh
111+ return ([KindConstraint me Row], me, M.insert v me m)
112+kindConstraintsForRow m REmpty = do
113+ me <- fresh
114+ return ([KindConstraint me Row], me, m)
115+kindConstraintsForRow m (RCons _ ty row) = do
116+ me <- fresh
117+ (cs1, n1, m1) <- kindConstraints m ty
118+ (cs2, n2, m2) <- kindConstraintsForRow m1 row
119+ return ((KindConstraint me Row) : (KindConstraint n1 Star) : (KindConstraint n2 Row) : cs1 ++ cs2, me, m2)
120+
121+solveKindConstraints :: [KindConstraint] -> KindSolution -> Check KindSolution
122+solveKindConstraints [] s = return s
123+solveKindConstraints all@(KindConstraint n k:cs) s = do
124+ guardWith "Occurs check failed" $ not $ kindOccursCheck False n k
125+ let s' = KindSolution $ replaceUnknownKind n k . runKindSolution s
126+ cs' <- fmap concat $ mapM (substituteKindConstraint n k) cs
127+ solveKindConstraints cs' s'
128+
129+substituteKindConstraint :: Int -> Kind -> KindConstraint -> Check [KindConstraint]
130+substituteKindConstraint n k (KindConstraint m l)
131+ | n == m = unifyKinds k l
132+ | otherwise = return [KindConstraint m (replaceUnknownKind n k l)]
133+
134+replaceUnknownKind :: Int -> Kind -> Kind -> Kind
135+replaceUnknownKind n k = f
136+ where
137+ f (KUnknown m) | m == n = k
138+ f (FunKind k1 k2) = FunKind (f k2) (f k2)
139+ f other = other
140+
141+unifyKinds :: Kind -> Kind -> Check [KindConstraint]
142+unifyKinds (KUnknown u1) (KUnknown u2) | u1 == u2 = return []
143+unifyKinds (KUnknown u) k = do
144+ guardWith "Occurs check failed" $ not $ kindOccursCheck False u k
145+ return [KindConstraint u k]
146+unifyKinds k (KUnknown u) = do
147+ guardWith "Occurs check failed" $ not $ kindOccursCheck False u k
148+ return [KindConstraint u k]
149+unifyKinds Star Star = return []
150+unifyKinds Row Row = return []
151+unifyKinds (FunKind k1 k2) (FunKind k3 k4) = do
152+ cs1 <- unifyKinds k1 k3
153+ cs2 <- unifyKinds k2 k4
154+ return $ cs1 ++ cs2
155+unifyKinds k1 k2 = throwError $ "Cannot unify " ++ show k1 ++ " with " ++ show k2 ++ "."
156+
157+kindOccursCheck :: Bool -> Int -> Kind -> Bool
158+kindOccursCheck b u (KUnknown u') | u == u' = b
159+kindOccursCheck _ u (FunKind k1 k2) = kindOccursCheck True u k1 || kindOccursCheck True u k2
160+kindOccursCheck _ _ _ = False
src/PureScript/TypeChecker/Monad.hsnew file+60
@@ -0,0 +1,60 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.TypeChecker.Monad
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances #-}
16+
17+module PureScript.TypeChecker.Monad where
18+
19+import PureScript.Types
20+import PureScript.Kinds
21+
22+import Control.Applicative
23+import Control.Monad.State
24+import Control.Monad.Error
25+
26+import Control.Arrow ((***))
27+
28+import qualified Data.Map as M
29+
30+data Environment = Environment
31+ { names :: M.Map String Type
32+ , types :: M.Map String Kind
33+ } deriving (Show)
34+
35+emptyEnvironment :: Environment
36+emptyEnvironment = Environment M.empty M.empty
37+
38+newtype Check a = Check { unCheck :: StateT (Environment, Int) (Either String) a } deriving (Functor, Monad, Applicative, MonadPlus, MonadState (Environment, Int), MonadError String)
39+
40+getEnv :: Check Environment
41+getEnv = fmap fst get
42+
43+putEnv :: Environment -> Check ()
44+putEnv env = fmap (const env *** id) get >>= put
45+
46+fresh :: Check Int
47+fresh = do
48+ (env, n) <- get
49+ put (env, n + 1)
50+ return n
51+
52+check :: Check a -> Either String (a, Environment)
53+check = fmap (id *** fst) . flip runStateT (emptyEnvironment, 0) . unCheck
54+
55+guardWith :: (MonadError e m) => e -> Bool -> m ()
56+guardWith _ True = return ()
57+guardWith e False = throwError e
58+
59+rethrow :: (MonadError e m) => (e -> e) -> m a -> m a
60+rethrow f = flip catchError $ \e -> throwError (f e)
src/PureScript/TypeChecker/Types.hsnew file+483
@@ -0,0 +1,483 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.TypeChecker.Types
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.TypeChecker.Types (
16+ TypeConstraint(..),
17+ TypeSolution(..),
18+ typeOf
19+) where
20+
21+import Data.List
22+import Data.Function
23+
24+import PureScript.Values
25+import PureScript.Types
26+import PureScript.TypeChecker.Monad
27+
28+import Control.Monad.State
29+import Control.Monad.Error
30+
31+import Control.Applicative
32+import Control.Arrow (Kleisli(..), (***), (&&&))
33+import qualified Control.Category as C
34+
35+import qualified Data.Map as M
36+
37+data TypeConstraint
38+ = TypeConstraint Int Type
39+ | RowConstraint Int Row deriving Show
40+
41+newtype TypeSolution = TypeSolution { runTypeSolution :: (Int -> Type, Int -> Row) }
42+
43+emptyTypeSolution :: TypeSolution
44+emptyTypeSolution = TypeSolution (TUnknown, RUnknown)
45+
46+typeOf :: String -> Value -> Check Type
47+typeOf name val = do
48+ me <- fresh
49+ (cs, n) <- typeConstraints (M.singleton name me) val
50+ solution <- solveTypeConstraints ((TypeConstraint me (TUnknown n)) : cs) emptyTypeSolution
51+ return $ varIfUnknown $ fst (runTypeSolution solution) n
52+
53+varIfUnknown :: Type -> Type
54+varIfUnknown = flip evalState M.empty . varIfUnknown'
55+ where
56+ varIfUnknown' :: Type -> State (M.Map Int String) Type
57+ varIfUnknown' (TUnknown n) = do
58+ m <- get
59+ case M.lookup n m of
60+ Nothing -> do
61+ let name = "t" ++ show (M.size m)
62+ put $ M.insert n name m
63+ return $ TypeVar name
64+ Just name -> return $ TypeVar name
65+ varIfUnknown' (Array t) = Array <$> varIfUnknown' t
66+ varIfUnknown' (Object row) = Object <$> varIfUnknown'' row
67+ varIfUnknown' (Function args ret) = Function <$> mapM varIfUnknown' args <*> varIfUnknown' ret
68+ varIfUnknown' (TypeApp t1 t2) = TypeApp <$> varIfUnknown' t1 <*> varIfUnknown' t2
69+ varIfUnknown' t = return t
70+ varIfUnknown'' :: Row -> State (M.Map Int String) Row
71+ varIfUnknown'' (RUnknown n) = do
72+ m <- get
73+ case M.lookup n m of
74+ Nothing -> do
75+ let name = "r" ++ show (M.size m)
76+ put $ M.insert n name m
77+ return $ RowVar name
78+ Just name -> return $ RowVar name
79+ varIfUnknown'' (RCons name ty row) = RCons name ty <$> varIfUnknown'' row
80+ varIfUnknown'' r = return r
81+
82+replaceVarsWithUnknowns :: Type -> Check Type
83+replaceVarsWithUnknowns = flip evalStateT M.empty . replaceVarsWithUnknowns'
84+ where
85+ replaceVarsWithUnknowns' :: Type -> StateT (M.Map String Int) Check Type
86+ replaceVarsWithUnknowns' (Array t) = Array <$> replaceVarsWithUnknowns' t
87+ replaceVarsWithUnknowns' (Object row) = Object <$> replaceVarsWithUnknowns'' row
88+ replaceVarsWithUnknowns' (Function args ret) = Function <$> mapM replaceVarsWithUnknowns' args <*> replaceVarsWithUnknowns' ret
89+ replaceVarsWithUnknowns' (TypeApp t1 t2) = TypeApp <$> replaceVarsWithUnknowns' t1 <*> replaceVarsWithUnknowns' t2
90+ replaceVarsWithUnknowns' (TypeVar var) = do
91+ m <- get
92+ n <- lift fresh
93+ case M.lookup var m of
94+ Nothing -> do
95+ put (M.insert var n m)
96+ return $ TUnknown n
97+ Just u -> return $ TUnknown u
98+ replaceVarsWithUnknowns' t = return t
99+ replaceVarsWithUnknowns'' :: Row -> StateT (M.Map String Int) Check Row
100+ replaceVarsWithUnknowns'' (RowVar var) = do
101+ m <- get
102+ n <- lift fresh
103+ case M.lookup var m of
104+ Nothing -> do
105+ put (M.insert var n m)
106+ return $ RUnknown n
107+ Just u -> return $ RUnknown u
108+ replaceVarsWithUnknowns'' (RCons name ty row) = RCons name <$> replaceVarsWithUnknowns' ty <*> replaceVarsWithUnknowns'' row
109+ replaceVarsWithUnknowns'' r = return r
110+
111+typeConstraints :: M.Map String Int -> Value -> Check ([TypeConstraint], Int)
112+typeConstraints _ (NumericLiteral _) = do
113+ me <- fresh
114+ return ([TypeConstraint me Number], me)
115+typeConstraints _ (StringLiteral _) = do
116+ me <- fresh
117+ return ([TypeConstraint me String], me)
118+typeConstraints _ (BooleanLiteral _) = do
119+ me <- fresh
120+ return ([TypeConstraint me Boolean], me)
121+typeConstraints m (ArrayLiteral vals) = do
122+ all <- mapM (typeConstraints m) vals
123+ let (cs, ns) = (concat . map fst &&& map snd) all
124+ me <- fresh
125+ return (cs ++ map (TypeConstraint me . Array . TUnknown) ns, me)
126+typeConstraints m (Unary op val) = do
127+ (cs, n1) <- typeConstraints m val
128+ me <- fresh
129+ return (cs ++ unaryOperatorConstraints op n1 me, me)
130+typeConstraints m (Binary op left right) = do
131+ (cs1, n1) <- typeConstraints m left
132+ (cs2, n2) <- typeConstraints m right
133+ me <- fresh
134+ return (cs1 ++ cs2 ++ binaryOperatorConstraints op n1 n2 me, me)
135+typeConstraints m (ObjectLiteral ps) = do
136+ all <- mapM (typeConstraints m . snd) ps
137+ let (cs, ns) = (concat . map fst &&& map snd) all
138+ me <- fresh
139+ let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
140+ return ((TypeConstraint me (Object (typesToRow tys))) : cs, me)
141+ where
142+ typesToRow [] = REmpty
143+ typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)
144+typeConstraints m (Indexer index val) = do
145+ (cs1, n1) <- typeConstraints m index
146+ (cs2, n2) <- typeConstraints m val
147+ me <- fresh
148+ return ((TypeConstraint n1 Number) : (TypeConstraint n2 (Array (TUnknown me))) : cs1 ++ cs2, me)
149+typeConstraints m (Accessor prop val) = do
150+ (cs, n1) <- typeConstraints m val
151+ me <- fresh
152+ rest <- fresh
153+ return ((TypeConstraint n1 (Object (RCons prop (TUnknown me) (RUnknown rest)))) : cs, me)
154+typeConstraints m (Abs args ret) = do
155+ ns <- replicateM (length args) fresh
156+ let m' = m `M.union` M.fromList (zipWith (,) args ns)
157+ (cs, n') <- typeConstraints m' ret
158+ me <- fresh
159+ return ((TypeConstraint me (Function (map TUnknown ns) (TUnknown n'))) : cs, me)
160+typeConstraints m (App f xs) = do
161+ (cs1, n1) <- typeConstraints m f
162+ all <- mapM (typeConstraints m) xs
163+ let (cs2, ns) = (concat . map fst &&& map snd) all
164+ me <- fresh
165+ return ((TypeConstraint n1 (Function (map TUnknown ns) (TUnknown me))) : cs1 ++ cs2, me)
166+typeConstraints m (Var var) =
167+ case M.lookup var m of
168+ Nothing -> do
169+ env <- getEnv
170+ case M.lookup var (names env) of
171+ Nothing -> throwError $ var ++ " is undefined"
172+ Just ty -> do
173+ me <- fresh
174+ replaced <- replaceVarsWithUnknowns ty
175+ return ([TypeConstraint me replaced], me)
176+ Just u -> do
177+ me <- fresh
178+ return ([TypeConstraint u (TUnknown me)], me)
179+typeConstraints m (Block ss) = do
180+ ret <- fresh
181+ (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m M.empty ret ss
182+ guardWith "Block is missing a return statement" allCodePathsReturn
183+ return (cs, ret)
184+typeConstraints m (Constructor c) = do
185+ env <- getEnv
186+ case M.lookup c (names env) of
187+ Nothing -> throwError $ c ++ " is undefined"
188+ Just ty -> do
189+ me <- fresh
190+ replaced <- replaceVarsWithUnknowns ty
191+ return ([TypeConstraint me replaced], me)
192+typeConstraints m (Case val binders) = do
193+ (cs1, n1) <- typeConstraints m val
194+ ret <- fresh
195+ cs2 <- typeConstraintsForBinders m n1 ret binders
196+ return (cs1 ++ cs2, ret)
197+typeConstraints m (TypedValue val ty) = do
198+ (cs, n1) <- typeConstraints m val
199+ return ([TypeConstraint n1 ty], n1)
200+ -- TODO: Kind-check the type
201+
202+unaryOperatorConstraints :: UnaryOperator -> Int -> Int -> [TypeConstraint]
203+unaryOperatorConstraints Negate val result = [TypeConstraint val Number, TypeConstraint result Number]
204+unaryOperatorConstraints Not val result = [TypeConstraint val Boolean, TypeConstraint result Boolean]
205+unaryOperatorConstraints BitwiseNot val result = [TypeConstraint val Number, TypeConstraint result Number]
206+
207+binaryOperatorConstraints :: BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]
208+binaryOperatorConstraints Add = symBinOpConstraints Number
209+binaryOperatorConstraints Subtract = symBinOpConstraints Number
210+binaryOperatorConstraints Multiply = symBinOpConstraints Number
211+binaryOperatorConstraints Divide = symBinOpConstraints Number
212+binaryOperatorConstraints Modulus = symBinOpConstraints Number
213+binaryOperatorConstraints LessThan = asymBinOpConstraints Number Boolean
214+binaryOperatorConstraints LessThanOrEqualTo = asymBinOpConstraints Number Boolean
215+binaryOperatorConstraints GreaterThan = asymBinOpConstraints Number Boolean
216+binaryOperatorConstraints GreaterThanOrEqualTo = asymBinOpConstraints Number Boolean
217+binaryOperatorConstraints BitwiseAnd = symBinOpConstraints Number
218+binaryOperatorConstraints BitwiseOr = symBinOpConstraints Number
219+binaryOperatorConstraints BitwiseXor = symBinOpConstraints Number
220+binaryOperatorConstraints ShiftLeft = symBinOpConstraints Number
221+binaryOperatorConstraints ShiftRight = symBinOpConstraints Number
222+binaryOperatorConstraints ZeroFillShiftRight = symBinOpConstraints Number
223+binaryOperatorConstraints EqualTo = equalityBinOpConstraints
224+binaryOperatorConstraints NotEqualTo = equalityBinOpConstraints
225+binaryOperatorConstraints And = symBinOpConstraints Boolean
226+binaryOperatorConstraints Or = symBinOpConstraints Boolean
227+binaryOperatorConstraints Concat = symBinOpConstraints String
228+
229+equalityBinOpConstraints :: Int -> Int -> Int -> [TypeConstraint]
230+equalityBinOpConstraints left right result = [TypeConstraint left (TUnknown right), TypeConstraint result Boolean]
231+
232+symBinOpConstraints :: Type -> Int -> Int -> Int -> [TypeConstraint]
233+symBinOpConstraints ty left right result = asymBinOpConstraints ty ty left right result
234+
235+asymBinOpConstraints :: Type -> Type -> Int -> Int -> Int -> [TypeConstraint]
236+asymBinOpConstraints ty res left right result = [TypeConstraint left ty, TypeConstraint right ty, TypeConstraint result res]
237+
238+typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map String Int)
239+typeConstraintsForBinder val (StringBinder _) = constantBinder val String
240+typeConstraintsForBinder val (NumberBinder _) = constantBinder val Number
241+typeConstraintsForBinder val (BooleanBinder _) = constantBinder val Boolean
242+typeConstraintsForBinder val (VarBinder name) = do
243+ me <- fresh
244+ return ([TypeConstraint me (TUnknown val)], M.singleton name me)
245+typeConstraintsForBinder val (NullaryBinder ctor) = do
246+ env <- getEnv
247+ case M.lookup ctor (names env) of
248+ Just ret -> do
249+ ret' <- replaceVarsWithUnknowns ret
250+ return ([TypeConstraint val ret'], M.empty)
251+ _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
252+typeConstraintsForBinder val (UnaryBinder ctor binder) = do
253+ env <- getEnv
254+ case M.lookup ctor (names env) of
255+ Just f@(Function [ty] ret) -> do
256+ obj <- fresh
257+ Function [ty'] ret' <- replaceVarsWithUnknowns f
258+ (cs, m1) <- typeConstraintsForBinder obj binder
259+ return ((TypeConstraint val ret') : (TypeConstraint obj ty') : cs, m1)
260+ Just _ -> throwError $ ctor ++ " is not a unary constructor"
261+ _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
262+typeConstraintsForBinder val (ObjectBinder props) = do
263+ row <- fresh
264+ rest <- fresh
265+ (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props
266+ return ((TypeConstraint val (Object (RUnknown row))) : cs, m1)
267+ where
268+ typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map String Int)
269+ typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row], M.empty)
270+ typeConstraintsForProperties nrow row ((name, binder):binders) = do
271+ propTy <- fresh
272+ (cs1, m1) <- typeConstraintsForBinder propTy binder
273+ (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders
274+ return (cs1 ++ cs2, M.union m1 m2)
275+typeConstraintsForBinder val (ArrayBinder binders rest) = do
276+ el <- fresh
277+ all <- mapM (typeConstraintsForBinder el) binders
278+ let (cs1, m1) = (concat . map fst &&& M.unions . map snd) all
279+ let arrayConstraint = TypeConstraint val (Array (TUnknown el))
280+ case rest of
281+ Nothing -> return (arrayConstraint : cs1, m1)
282+ Just binder -> do
283+ (cs2, m2) <- typeConstraintsForBinder val binder
284+ return (arrayConstraint : cs1 ++ cs2, M.union m1 m2)
285+
286+constantBinder :: Int -> Type -> Check ([TypeConstraint], M.Map String Int)
287+constantBinder val ty = return ([TypeConstraint val ty], M.empty)
288+
289+typeConstraintsForBinders :: M.Map String Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]
290+typeConstraintsForBinders _ _ _ [] = return []
291+typeConstraintsForBinders m nval ret ((binder, val):bs) = do
292+ (cs1, m1) <- typeConstraintsForBinder nval binder
293+ (cs2, n2) <- typeConstraints (M.union m m1) val
294+ cs3 <- typeConstraintsForBinders m nval ret bs
295+ return ((TypeConstraint n2 (TUnknown ret)) : cs1 ++ cs2 ++ cs3)
296+
297+typeConstraintsForStatement :: M.Map String Int -> M.Map String Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map String Int)
298+typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do
299+ case M.lookup name (m `M.union` mass) of
300+ Nothing -> do
301+ (cs1, n1) <- typeConstraints m val
302+ return $ (cs1, False, M.insert name n1 mass)
303+ Just ty -> throwError $ "Variable with name " ++ name ++ " already exists."
304+typeConstraintsForStatement m mass ret (Assignment tgt val) = do
305+ (cs1, n1) <- typeConstraints m val
306+ cs2 <- typeConstraintsForAssignmentTarget m mass n1 tgt
307+ return (cs1 ++ cs2, False, mass)
308+typeConstraintsForStatement m mass ret (While val inner) = do
309+ (cs1, n1) <- typeConstraints m val
310+ (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner
311+ return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn, mass)
312+typeConstraintsForStatement m mass ret (IfThenElse val thens Nothing) = do
313+ (cs1, n1) <- typeConstraints m val
314+ (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret thens
315+ return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn, mass)
316+typeConstraintsForStatement m mass ret (IfThenElse val thens (Just elses)) = do
317+ (cs1, n1) <- typeConstraints m val
318+ (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens
319+ (cs3, allCodePathsReturn2, _) <- typeConstraintsForBlock m mass ret elses
320+ return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2, mass)
321+typeConstraintsForStatement m mass ret (For (init, cond, cont) inner) = do
322+ (cs1, b1, mass1) <- typeConstraintsForStatement m mass ret init
323+ guardWith "Cannot return from inside for" $ not b1
324+ (cs2, n1) <- typeConstraints (m `M.union` mass1) cond
325+ (cs3, b2, mass2) <- typeConstraintsForStatement (m `M.union` mass1) mass1 ret cont
326+ guardWith "Cannot return from inside for" $ not b2
327+ (cs4, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass2) mass2 ret inner
328+ return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2 ++ cs3 ++ cs4, allCodePathsReturn, mass)
329+typeConstraintsForStatement m mass ret (Return val) = do
330+ (cs1, n1) <- typeConstraints (m `M.union` mass) val
331+ return ((TypeConstraint n1 (TUnknown ret)) : cs1, True, mass)
332+
333+typeConstraintsForAssignmentTarget :: M.Map String Int -> M.Map String Int -> Int -> AssignmentTarget -> Check [TypeConstraint]
334+typeConstraintsForAssignmentTarget m mass nval (AssignVariable var) =
335+ case M.lookup var mass of
336+ Nothing -> throwError $ "No local variable with name " ++ var
337+ Just ty -> do
338+ return [TypeConstraint nval (TUnknown ty)]
339+typeConstraintsForAssignmentTarget m mass nval (AssignArrayIndex index tgt) = do
340+ arr <- fresh
341+ (cs1, n1) <- typeConstraints (m `M.union` mass) index
342+ cs2 <- typeConstraintsForAssignmentTarget m mass arr tgt
343+ return $ (TypeConstraint arr (Array (TUnknown nval))) : (TypeConstraint n1 Number) : cs1 ++ cs2
344+typeConstraintsForAssignmentTarget m mass nval (AssignObjectProperty prop tgt) = do
345+ obj <- fresh
346+ row <- fresh
347+ cs <- typeConstraintsForAssignmentTarget m mass obj tgt
348+ return $ (TypeConstraint obj (Object (RCons prop (TUnknown nval) $ RUnknown row))) : cs
349+
350+typeConstraintsForBlock :: M.Map String Int -> M.Map String Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map String Int)
351+typeConstraintsForBlock _ mass _ [] = return ([], False, mass)
352+typeConstraintsForBlock m mass ret (s:ss) = do
353+ (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s
354+ case (b1, ss) of
355+ (True, []) -> return (cs1, True, mass1)
356+ (True, _) -> throwError "Unreachable code"
357+ (False, ss) -> do
358+ (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss
359+ return (cs1 ++ cs2, b2, mass2)
360+
361+solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution
362+solveTypeConstraints [] s = return s
363+solveTypeConstraints all@(TypeConstraint n t:cs) s = do
364+ guardWith "Occurs check failed" $ not $ typeOccursCheck False n t
365+ let s' = let (f, g) = runTypeSolution s
366+ in TypeSolution (replaceTypeInType n t . f, replaceTypeInRow n t . g)
367+ cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs
368+ solveTypeConstraints cs' s'
369+solveTypeConstraints (RowConstraint n r:cs) s = do
370+ guardWith "Occurs check failed" $ not $ rowOccursCheck False n r
371+ let s' = let (f, g) = runTypeSolution s
372+ in TypeSolution $ (replaceRowInType n r . f, replaceRowInRow n r . g)
373+ cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs
374+ solveTypeConstraints cs' s'
375+
376+substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]
377+substituteTypeInConstraint n s (TypeConstraint m t)
378+ | n == m = unifyTypes s t
379+ | otherwise = return [TypeConstraint m (replaceTypeInType n s t)]
380+substituteTypeInConstraint n s (RowConstraint m r)
381+ = return [RowConstraint m (replaceTypeInRow n s r)]
382+
383+substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]
384+substituteRowInConstraint n r (TypeConstraint m t)
385+ = return [TypeConstraint m (replaceRowInType n r t)]
386+substituteRowInConstraint n r (RowConstraint m r1)
387+ | m == n = unifyRows r r1
388+ | otherwise = return [RowConstraint m (replaceRowInRow n r r1)]
389+
390+replaceTypeInType :: Int -> Type -> Type -> Type
391+replaceTypeInType n t (TUnknown m) | m == n = t
392+replaceTypeInType n t (Array t1) = Array $ replaceTypeInType n t t1
393+replaceTypeInType n t (Object row) = Object $ replaceTypeInRow n t row
394+replaceTypeInType n t (Function args ret) = Function (map (replaceTypeInType n t) args) (replaceTypeInType n t ret)
395+replaceTypeInType n t (TypeApp t1 t2) = TypeApp (replaceTypeInType n t t1) (replaceTypeInType n t t2)
396+replaceTypeInType _ _ other = other
397+
398+replaceTypeInRow :: Int -> Type -> Row -> Row
399+replaceTypeInRow n t (RCons name ty row) = RCons name (replaceTypeInType n t ty) (replaceTypeInRow n t row)
400+replaceTypeInRow n t other = other
401+
402+replaceRowInType :: Int -> Row -> Type -> Type
403+replaceRowInType n r (Array t1) = Array $ replaceRowInType n r t1
404+replaceRowInType n r (Object row) = Object $ replaceRowInRow n r row
405+replaceRowInType n r (Function args ret) = Function (map (replaceRowInType n r) args) (replaceRowInType n r ret)
406+replaceRowInType n r (TypeApp t1 t2) = TypeApp (replaceRowInType n r t1) (replaceRowInType n r t2)
407+replaceRowInType _ _ other = other
408+
409+replaceRowInRow :: Int -> Row -> Row -> Row
410+replaceRowInRow n r (RUnknown m) | m == n = r
411+replaceRowInRow n r (RCons name ty row) = RCons name (replaceRowInType n r ty) (replaceRowInRow n r row)
412+replaceRowInRow _ _ other = other
413+
414+unifyTypes :: Type -> Type -> Check [TypeConstraint]
415+unifyTypes (TUnknown u1) (TUnknown u2) | u1 == u2 = return []
416+unifyTypes (TUnknown u) t = do
417+ guardWith "Occurs check failed" $ not $ typeOccursCheck False u t
418+ return [TypeConstraint u t]
419+unifyTypes t (TUnknown u) = do
420+ guardWith "Occurs check failed" $ not $ typeOccursCheck False u t
421+ return [TypeConstraint u t]
422+unifyTypes Number Number = return []
423+unifyTypes String String = return []
424+unifyTypes Boolean Boolean = return []
425+unifyTypes (Array s) (Array t) = unifyTypes s t
426+unifyTypes (Object row1) (Object row2) = unifyRows row1 row2
427+unifyTypes (Function args1 ret1) (Function args2 ret2) = do
428+ guardWith "Function applied to incorrect number of args" $ length args1 == length args2
429+ cs1 <- fmap concat $ zipWithM unifyTypes args1 args2
430+ cs2 <- unifyTypes ret1 ret2
431+ return $ cs1 ++ cs2
432+unifyTypes (TypeVar v1) (TypeVar v2) | v1 == v2 = return []
433+unifyTypes (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []
434+unifyTypes (TypeVar v1) (TypeVar v2) = return []
435+unifyTypes (TypeApp t1 t2) (TypeApp t3 t4) = do
436+ cs1 <- unifyTypes t1 t3
437+ cs2 <- unifyTypes t2 t4
438+ return $ cs1 ++ cs2
439+unifyTypes t1 t2 = throwError $ "Cannot unify " ++ show t1 ++ " with " ++ show t2 ++ "."
440+
441+unifyRows :: Row -> Row -> Check [TypeConstraint]
442+unifyRows r1 r2 =
443+ let
444+ (s1, r1') = toList r1
445+ (s2, r2') = toList r2
446+ int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
447+ sd1 = [ (name, t1) | (name, t1) <- s1, not (elem name (map fst s2)) ]
448+ sd2 = [ (name, t2) | (name, t2) <- s2, not (elem name (map fst s1)) ]
449+ in rethrow (const $ "Cannot unify " ++ show r1 ++ " with " ++ show r2) $ do
450+ cs1 <- fmap concat $ mapM (uncurry unifyTypes) int
451+ cs2 <- unifyRows' sd1 r1' sd2 r2'
452+ return $ cs1 ++ cs2
453+ where
454+ unifyRows' :: [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
455+ unifyRows' [] (RUnknown u) sd r = do
456+ guardWith "Occurs check failed" $ not $ rowOccursCheck False u r
457+ return [RowConstraint u (fromList (sd, r))]
458+ unifyRows' ((name, ty):row) r others (RUnknown u) = do
459+ u' <- fresh
460+ cs <- unifyRows' row r others (RUnknown u')
461+ return [ RowConstraint u (RCons name ty (RUnknown u')) ]
462+ unifyRows' [] REmpty [] REmpty = return []
463+ unifyRows' sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ show (fromList (sd1, r1)) ++ " with " ++ show (fromList (sd2, r2)) ++ "."
464+ toList :: Row -> ([(String, Type)], Row)
465+ toList (RCons name ty row) = let (tys, rest) = toList row
466+ in ((name, ty):tys, rest)
467+ toList r = ([], r)
468+ fromList :: ([(String, Type)], Row) -> Row
469+ fromList ([], r) = r
470+ fromList ((name, t):ts, r) = RCons name t (fromList (ts, r))
471+
472+typeOccursCheck :: Bool -> Int -> Type -> Bool
473+typeOccursCheck b u (TUnknown u') | u == u' = b
474+typeOccursCheck _ u (Array t) = typeOccursCheck True u t
475+typeOccursCheck _ u (Object row) = rowOccursCheck True u row
476+typeOccursCheck _ u (Function args ret) = any (typeOccursCheck True u) args || typeOccursCheck True u ret
477+typeOccursCheck _ u (TypeApp s t) = typeOccursCheck True u s || typeOccursCheck True u t
478+typeOccursCheck _ _ _ = False
479+
480+rowOccursCheck :: Bool -> Int -> Row -> Bool
481+rowOccursCheck b u (RUnknown u') | u == u' = b
482+rowOccursCheck _ u (RCons name ty row) = typeOccursCheck True u ty || rowOccursCheck True u row
483+rowOccursCheck _ _ _ = False
src/PureScript/Types.hsnew file+40
@@ -0,0 +1,40 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : Purescript.Types
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+{-# LANGUAGE DeriveFunctor #-}
16+
17+module PureScript.Types (
18+ Type (..),
19+ Row(..)
20+) where
21+
22+import Data.List (intercalate)
23+
24+data Type
25+ = TUnknown Int
26+ | Number
27+ | String
28+ | Boolean
29+ | Array Type
30+ | Object Row
31+ | Function [Type] Type
32+ | TypeVar String
33+ | TypeConstructor String
34+ | TypeApp Type Type deriving Show
35+
36+data Row
37+ = RUnknown Int
38+ | RowVar String
39+ | REmpty
40+ | RCons String Type Row deriving Show
src/PureScript/Values.hsnew file+92
@@ -0,0 +1,92 @@
1+-----------------------------------------------------------------------------
2+--
3+-- Module : PureScript.Values
4+-- Copyright : (c) Phil Freeman 2013
5+-- License : MIT
6+--
7+-- Maintainer : Phil Freeman <paf31@cantab.net>
8+-- Stability : experimental
9+-- Portability :
10+--
11+-- |
12+--
13+-----------------------------------------------------------------------------
14+
15+module PureScript.Values (
16+ UnaryOperator (..),
17+ BinaryOperator (..),
18+ Value (..),
19+ Statement (..),
20+ Binder (..),
21+ AssignmentTarget (..)
22+) where
23+
24+import PureScript.Types
25+
26+data UnaryOperator
27+ = Negate
28+ | Not
29+ | BitwiseNot deriving (Show, Eq)
30+
31+data BinaryOperator
32+ = Add
33+ | Subtract
34+ | Multiply
35+ | Divide
36+ | Modulus
37+ | EqualTo
38+ | NotEqualTo
39+ | LessThan
40+ | LessThanOrEqualTo
41+ | GreaterThan
42+ | GreaterThanOrEqualTo
43+ | And
44+ | Or
45+ | BitwiseAnd
46+ | BitwiseOr
47+ | BitwiseXor
48+ | ShiftLeft
49+ | ShiftRight
50+ | ZeroFillShiftRight
51+ | Concat deriving (Show, Eq)
52+
53+data Value
54+ = NumericLiteral (Either Integer Double)
55+ | StringLiteral String
56+ | BooleanLiteral Bool
57+ | Unary UnaryOperator Value
58+ | Binary BinaryOperator Value Value
59+ | ArrayLiteral [Value]
60+ | Indexer Value Value
61+ | ObjectLiteral [(String, Value)]
62+ | Accessor String Value
63+ | Abs [String] Value
64+ | App Value [Value]
65+ | Var String
66+ | Block [Statement]
67+ | Constructor String
68+ | Case Value [(Binder, Value)]
69+ | TypedValue Value Type deriving Show
70+
71+data Statement
72+ = VariableIntroduction String Value
73+ | Assignment AssignmentTarget Value
74+ | While Value [Statement]
75+ | For (Statement, Value, Statement) [Statement]
76+ | IfThenElse (Value) [Statement] (Maybe [Statement])
77+ | Return Value deriving Show
78+
79+data Binder
80+ = BooleanBinder Bool
81+ | StringBinder String
82+ | NumberBinder (Either Integer Double)
83+ | VarBinder String
84+ | NullaryBinder String
85+ | UnaryBinder String Binder
86+ | ObjectBinder [(String, Binder)]
87+ | ArrayBinder [Binder] (Maybe Binder) deriving Show
88+
89+data AssignmentTarget
90+ = AssignVariable String
91+ | AssignObjectProperty String AssignmentTarget
92+ | AssignArrayIndex Value AssignmentTarget deriving Show
src/Tests.hsdeleted−141
@@ -1,141 +0,0 @@
1−module Tests (runTests) where
2−
3−import Prelude.Compat
4−import Data.List
5−import Control.Applicative
6−import Control.Monad
7−
8−import System.Process
9−import System.FilePath
10−import System.IO
11−import System.Directory
12−
13−-------------------------------------------------------------------------------
14−testsDir :: IO (FilePath, FilePath)
15−-------------------------------------------------------------------------------
16−testsDir = do
17− baseDir <- getCurrentDirectory
18− return (baseDir </> "purescript-tests", baseDir)
19−
20−-------------------------------------------------------------------------------
21−runTests :: IO ()
22−-------------------------------------------------------------------------------
23−runTests = do
24−
25− (outputDir, baseDir) <- testsDir
26−
27− outputDirExists <- doesDirectoryExist outputDir
28− when outputDirExists $ removeDirectoryRecursive outputDir
29− createDirectory outputDir
30−
31− let srcDir = outputDir </> "src"
32− createDirectory srcDir
33−
34− callProcess "git" ["clone", "--branch", "v0.13.8", "--depth", "1", "https://github.com/purescript/purescript.git"]
35− let passingDir = baseDir </> "purescript" </> "tests" </> "purs" </> "passing"
36− passingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents passingDir
37−
38− setCurrentDirectory outputDir
39−
40− fetchPackages
41−
42− let tests = filter (`notElem` skipped) passingTestCases
43−
44− tmp <- getTemporaryDirectory
45− createDirectoryIfMissing False (tmp </> logpath)
46− outputFile <- openFile (tmp </> logpath </> logfile) WriteMode
47− hClose outputFile
48−
49− -- Run the tests
50− --
51− forM_ tests $ \inputFile -> do
52− --
53− -- Compile/build
54− --
55− putStrLn $ "Compiling test " ++ inputFile ++ " ..."
56− setCurrentDirectory outputDir
57− copyFile (passingDir </> inputFile) (srcDir </> inputFile)
58−
59− let testCaseDir = passingDir </> (takeWhile (/='.') inputFile)
60− testCaseDirExists <- doesDirectoryExist testCaseDir
61− when testCaseDirExists $ callProcess "cp" ["-R", testCaseDir, srcDir]
62−
63− callProcess "rm" ["-rf", "output"]
64− callProcess "rm" ["-rf", "Main"]
65− callProcess "spago" ["build"]
66− --
67− -- Run executable file
68− --
69− outputFile <- openFile (tmp </> logpath </> logfile) AppendMode
70− hPutStrLn outputFile ("\n" ++ inputFile ++ ":")
71− proc <- runProcess ("./" </> "Main") [] Nothing Nothing Nothing (Just outputFile) Nothing
72−
73− removeFile (srcDir </> inputFile)
74− when testCaseDirExists $ callProcess "rm" ["-rf", srcDir </> (takeWhile (/='.') inputFile)]
75−
76− -- TODO: support failing test cases
77− --
78− -- let failing = baseDir </> "examples" </> "failing"
79− -- failingTestCases <- sort . filter (".purs" `isSuffixOf`) <$> getDirectoryContents failing
80− --
81−
82− setCurrentDirectory baseDir
83− putStrLn "PureScript tests finished"
84− putStrLn $ "Total tests available: " ++ show (length passingTestCases)
85− putStrLn $ "Tests run: " ++ show (length tests)
86− putStrLn $ "Tests skipped: " ++ show (length skipped)
87−
88−-------------------------------------------------------------------------------
89−packages :: [String]
90−-------------------------------------------------------------------------------
91−packages =
92− [ "arrays"
93− , "assert"
94− , "console"
95− , "control"
96− , "effect"
97− , "foldable-traversable"
98− , "functions"
99− , "generics-rep"
100− , "invariant"
101− , "newtype"
102− , "partial"
103− , "prelude"
104− , "proxy"
105− , "refs"
106− , "st"
107− , "type-equality"
108− , "typelevel-prelude"
109− ]
110−
111−-------------------------------------------------------------------------------
112−fetchPackages :: IO ()
113−-------------------------------------------------------------------------------
114−fetchPackages = do
115− callProcess "spago" ["init"]
116− callCommand "sed '$s/\\(}\\)/, backend = \"psgo\"\\1/' < spago.dhall | dhall format > spago.tmp"
117− callCommand "mv spago.tmp spago.dhall"
118−
119− mapM (callProcess "spago" . (\p -> ["install", p])) packages
120− return ()
121−
122−-------------------------------------------------------------------------------
123−skipped :: [String]
124−-------------------------------------------------------------------------------
125−skipped =
126− [ "2172.purs" -- foreign in Main needed (test manually)
127− , "EffFn.purs" -- foreign in Main needed (test manually)
128− , "FunWithFunDeps.purs" -- foreign in Main needed (test manually)
129− , "NumberLiterals.purs" -- unreliable float string comparison (test manually)
130− , "PolyLabels.purs" -- foreign in Main needed (test manually)
131− , "RowUnion.purs" -- foreign in Main needed (test manually)
132− , "ShadowedModuleName.purs" -- ?
133− , "StringEdgeCases.purs" -- javascript char encoding specific
134− , "StringEscapes.purs" -- Partially javascript-char-encoding-specific (test manually)
135− ]
136−
137−logpath :: FilePath
138−logpath = "purescript-output"
139−
140−logfile :: FilePath
141−logfile = "purescript-tests.out"
stack.nixdeleted−23
@@ -1,23 +0,0 @@
1−#
2−# You may need to manually run `unset STACK_IN_NIX_SHELL`
3−# (doesn't work from a `shellHook`; see: https://github.com/commercialhaskell/stack/issues/5000
4−#
5−#
6−# You may need to set LC_ALL when building, e.g.
7−# LC_ALL=en_US.iso88591 stack --nix build; see e.g. https://github.com/koalaman/shellcheck/issues/324
8−#
9−#
10−{ pkgs ?
11− import (builtins.fetchTarball {
12− name = "nixos-release-19.03";
13− url = https://github.com/nixos/nixpkgs/archive/34c7eb7545d155cc5b6f499b23a7cb1c96ab4d59.tar.gz;
14− sha256 = "11z6ajj108fy2q5g8y4higlcaqncrbjm3dnv17pvif6avagw4mcb";
15− }) {}
16−}:
17−
18−pkgs.haskell.lib.buildStackProject {
19− name = "default-stack-shell";
20− ghc = pkgs.haskell.compiler.ghc865;
21− buildInputs = with pkgs; [git git-lfs gmp ncurses zlib];
22− LANG = "en_US.UTF-8";
23−}
stack.yamldeleted−24
@@ -1,24 +0,0 @@
1−resolver: lts-13.26
2−
3−packages:
4−- .
5−
6−extra-deps:
7−- git: https://github.com/purescript/purescript
8− commit: 9cad73ed8ea7df3011032ddbd2f3de5a0c08629c
9−- happy-1.19.9
10−- language-javascript-0.7.0.0
11−- network-3.0.1.1
12−- these-1.0.1
13−- semialign-1
14−
15−nix:
16− enable: false
17− shell-file: stack.nix
18−
19−flags:
20− aeson-pretty:
21− lib-only: true
22− these:
23− assoc: false
24− quickcheck: false
support/ffi-loader.godeleted−30
@@ -1,30 +0,0 @@
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-enums"
12− _ "github.com/purescript-native/go-ffi/purescript-exceptions"
13− _ "github.com/purescript-native/go-ffi/purescript-foldable-traversable"
14− _ "github.com/purescript-native/go-ffi/purescript-functions"
15− _ "github.com/purescript-native/go-ffi/purescript-globals"
16− _ "github.com/purescript-native/go-ffi/purescript-integers"
17− _ "github.com/purescript-native/go-ffi/purescript-lazy"
18− _ "github.com/purescript-native/go-ffi/purescript-math"
19− _ "github.com/purescript-native/go-ffi/purescript-partial"
20− _ "github.com/purescript-native/go-ffi/purescript-prelude"
21− _ "github.com/purescript-native/go-ffi/purescript-random"
22− _ "github.com/purescript-native/go-ffi/purescript-refs"
23− _ "github.com/purescript-native/go-ffi/purescript-st"
24− _ "github.com/purescript-native/go-ffi/purescript-strings"
25− _ "github.com/purescript-native/go-ffi/purescript-unfoldable"
26−)
27−
28−// Add your own FFI packages here.
29−
30−import ()
support/go.mod.ffi-loaderdeleted−2
@@ -1,2 +0,0 @@
1−module $PROJECT/purescript-native/ffi-loader
2−
support/go.mod.outputdeleted−2
@@ -1,2 +0,0 @@
1−module $PROJECT/purescript-native/output
2−
support/go.mod.workingdeleted−1
@@ -1 +0,0 @@
1−module $PROJECT/example
test/Spec.hsdeleted−2
@@ -1,2 +0,0 @@
1−main :: IO ()
2−main = putStrLn "Test suite not yet implemented"