git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
80 files changed+2726−2737
since splitsnapshots
unifiedsplit
.gitignore+15 ChangeLog.md+3 LICENSE+26−16 PureScript.cabal−38 README-go.md+48 README.md+38−12 Setup.hs+2 Setup.lhs−6 app/Main.hs+250 default.nix+23 examples/.gitignore−1 examples/Arrays.ps−13 examples/Assign.ps−5 examples/Conditional.ps−5 examples/Console.js−19 examples/Console.ps−19 examples/FFI.ps−5 examples/Foreach.js−1 examples/Foreach.ps−5 examples/Guards.ps−3 examples/IfThenElse.ps−24 examples/List.js−7 examples/List.ps−22 examples/Match.ps−3 examples/Maybe.js−5 examples/Maybe.ps−10 examples/NamedPatterns.ps−6 examples/Nested.ps−3 examples/Objects.ps−9 examples/Operators.ps−19 examples/Patterns.ps−8 examples/Person.ps−7 examples/ReadShow.ps−5 examples/Recursion.ps−4 examples/TypeDecl.ps−12 examples/TypeSynonyms.ps−13 examples/iota.ps−5 examples/runAll.test−23 examples/runMain.js−1 examples/s.ps−1 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−73 src/PureScript.hs−33 src/PureScript/CodeGen.hs−21 src/PureScript/CodeGen/Common.hs−80 src/PureScript/CodeGen/Common/Gen.hs−31 src/PureScript/CodeGen/Externs.hs−105 src/PureScript/CodeGen/JS.hs−260 src/PureScript/Declarations.hs−30 src/PureScript/Kinds.hs−25 src/PureScript/Names.hs−26 src/PureScript/Parser.hs−26 src/PureScript/Parser/Common.hs−176 src/PureScript/Parser/Declarations.hs−76 src/PureScript/Parser/Types.hs−90 src/PureScript/Parser/Values.hs−255 src/PureScript/TypeChecker.hs−88 src/PureScript/TypeChecker/Kinds.hs−168 src/PureScript/TypeChecker/Monad.hs−67 src/PureScript/TypeChecker/Synonyms.hs−58 src/PureScript/TypeChecker/Types.hs−571 src/PureScript/Types.hs−42 src/PureScript/Values.hs−101 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,8 +1,23 @@
11dist
22cabal-dev
3+.cabal-sandbox
4+cabal.sandbox.config
35*.o
46*.hi
57*.chi
68*.chs.h
79*.lksh*
810.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.mdnew file+3
@@ -0,0 +1,3 @@
1+# Changelog for pscpp
2+
3+## Unreleased changes
LICENSE+26−16
@@ -1,20 +1,30 @@
1−The MIT License (MIT)
1+Copyright Andy Arvanitis (c) 2018
22
3−Copyright (c) 2013 Phil Freeman
3+All rights reserved.
44
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:
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are met:
117
12−The above copyright notice and this permission notice shall be included in all
13−copies or substantial portions of the Software.
8+ * Redistributions of source code must retain the above copyright
9+ notice, this list of conditions and the following disclaimer.
1410
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.
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.
PureScript.cabaldeleted−38
@@ -1,38 +0,0 @@
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, syb -any, cmdtheline -any,
17− containers -any, mtl -any, parsec -any, utf8-string -any
18− exposed-modules: PureScript PureScript.Declarations PureScript.Names PureScript.TypeChecker.Synonyms
19− PureScript.CodeGen.Externs PureScript.CodeGen.JS
20− PureScript.CodeGen.Common.Gen PureScript.CodeGen.Common Main
21− PureScript.CodeGen PureScript.Kinds PureScript.Parser
22− PureScript.TypeChecker PureScript.Types PureScript.Values
23− PureScript.Parser.Common PureScript.Parser.Declarations
24− PureScript.Parser.Types PureScript.Parser.Values
25− PureScript.TypeChecker.Kinds PureScript.TypeChecker.Monad
26− PureScript.TypeChecker.Types
27− exposed: True
28− buildable: True
29− hs-source-dirs: src
30− other-modules:
31−
32−executable psc
33− build-depends: base -any, cmdtheline -any, containers -any,
34− mtl -any, parsec -any, utf8-string -any
35− main-is: Main.hs
36− buildable: True
37− hs-source-dirs: src
38− other-modules:
README-go.mdnew file+48
@@ -0,0 +1,48 @@
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+38−12
@@ -1,15 +1,41 @@
1−purescript
2−==========
1+[![PureScript](https://raw.githubusercontent.com/purescript/purescript/master/logo.png)](http://purescript.org)
32
4−A small strongly, statically typed compile-to-JS language with basic extensible records and type-safe blocks
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.
54
6−## Current Features
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).
76
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
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+---
Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
Setup.lhsdeleted−6
@@ -1,6 +0,0 @@
1−#!/usr/bin/runhaskell
2−> module Main where
3−> import Distribution.Simple
4−> main :: IO ()
5−> main = defaultMain
6−
app/Main.hsnew file+250
@@ -0,0 +1,250 @@
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.nixnew file+23
@@ -0,0 +1,23 @@
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/.gitignoredeleted−1
@@ -1 +0,0 @@
1−tests
examples/Arrays.psdeleted−13
@@ -1,13 +0,0 @@
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−data Tree = One Number | Some [Tree]
10−
11−test3 = \tree, sum -> case tree of
12− One n -> n
13− Some [n1, n2 : rest] -> test3(n1, sum) * 10 + test3(n2, sum) * 5 + sum(rest)
examples/Assign.psdeleted−5
@@ -1,5 +0,0 @@
1−sum = \n -> do
2− var x = 0
3− for i <- 0 until n:
4− x = x + i
5− return x
examples/Conditional.psdeleted−5
@@ -1,5 +0,0 @@
1−fns = \f -> if f true then f else \x -> x
2−
3−bin = \x -> if x && !x then x else x
4−
5−not = \x -> if x then false else true
examples/Console.jsdeleted−19
@@ -1,19 +0,0 @@
1−// data IO a = \ -> a
2−
3−// ret :: forall a. a -> IO a
4−var ret = function(a) {
5− return function() { return a; };
6−}
7−
8−// (>>=) :: forall a b. IO a -> (a -> IO b) -> IO b
9−var $62$62$61 = function(first) {
10− return function (f) {
11− return function () {
12− var a = first();
13− return f(a)();
14− };
15− };
16−};
17−
18−// putStrLn :: String -> IO {}
19−var putStrLn = function(str) { return function() { console.log(str); return {}; }; };
examples/Console.psdeleted−19
@@ -1,19 +0,0 @@
1−data IO a = IO
2−
3−extern ret :: forall a. a -> IO a
4−
5−extern (>>=) :: forall a b. IO a -> (a -> IO b) -> IO b
6−
7−(*>) = \a -> \b -> a >>= \x -> b
8−
9−extern putStrLn :: String -> IO {}
10−
11−replicateM_ :: forall a. Number -> IO a -> IO {}
12−replicateM_ = \n -> \x -> do
13− var io = ret {}
14− for i <- 0 until n:
15− io = x *> io
16− return io
17−
18−main = replicateM_ 10 (putStrLn "Hello World!")
19−
examples/FFI.psdeleted−5
@@ -1,5 +0,0 @@
1−extern foo :: (String) -> String
2−
3−bar :: (String) -> String
4−
5−bar = \x -> foo(x ++ "bar")
examples/Foreach.jsdeleted−1
@@ -1 +0,0 @@
1−console.log(sum([1,2,3,4,5]));
examples/Foreach.psdeleted−5
@@ -1,5 +0,0 @@
1−sum = \ns -> do
2− var total = 0
3− foreach n in ns:
4− total = total + n
5− return total
examples/Guards.psdeleted−3
@@ -1,3 +0,0 @@
1−collatz = \x -> case x of
2− y | y % 2 == 0 -> y / 2
3− y -> y * 3 + 1
examples/IfThenElse.psdeleted−24
@@ -1,24 +0,0 @@
1−testIf = do
2− var x = 0
3− if x == 0:
4− x = x + 1
5− return x
6−
7−testIfElse = do
8− var x = 0
9− if x == 0:
10− x = x + 1
11− else:
12− x = x - 1
13− return x
14−
15−testIfElseIf = \x -> do
16− var y = x
17− while y > 1:
18− if y % 3 == 0:
19− y = y / 3
20− else if y % 3 == 1:
21− y = (y - 1) % 3
22− else:
23− y = y * 4 + 1
24− return y
examples/List.jsdeleted−7
@@ -1,7 +0,0 @@
1−var l1 = Cons({ head: 1, tail: Nil });
2−var l2 = Cons({ head: 2, tail: Nil });
3−var l3 = Cons({ head: l1, tail: Cons({ head: l2, tail: Nil }) });
4−var flat = flatten(l3);
5−var f1 = flat.value.head;
6−var f2 = flat.value.tail.value.head
7−console.log([f1, f2]);
examples/List.psdeleted−22
@@ -1,22 +0,0 @@
1−data List a
2− = Nil
3− | Cons
4− { head :: a
5− ; tail :: List a
6− }
7−
8−isNull = \l -> case l of
9− Nil -> true
10− _ -> false
11−
12−concat = \l1 -> \l2 -> case l1 of
13− Nil -> l2
14− Cons x -> Cons
15− { head: x.head
16− , tail: concat x.tail l2
17− }
18−
19−flatten = \xss -> case xss of
20− Nil -> Nil
21− Cons cons -> concat cons.head (flatten cons.tail)
22−
examples/Match.psdeleted−3
@@ -1,3 +0,0 @@
1−data Foo a = Foo
2−
3−foo = \f -> case f of Foo -> "foo"
examples/Maybe.jsdeleted−5
@@ -1,5 +0,0 @@
1−console.log(bind(Just("a"))(function(a) {
2− return bind(Just("b"))(function(b) {
3− return Just(a + b);
4− });
5−}));
examples/Maybe.psdeleted−10
@@ -1,10 +0,0 @@
1−data Maybe a = Nothing | Just a
2−
3−maybe :: forall a b. b -> (a -> b) -> Maybe a -> b
4−maybe = \b -> \f -> \m -> case m of
5− Nothing -> b
6− Just a -> f a
7−
8−fmap = \m -> \f -> maybe Nothing (\a -> Just (f a)) m
9−
10−bind = \m -> \f -> maybe Nothing f m
examples/NamedPatterns.psdeleted−6
@@ -1,6 +0,0 @@
1−foo = \x -> case x of
2− y@{ foo = "Foo" } -> y
3− y -> (do
4− var copy = y
5− copy.foo = "Bar"
6− return copy)
examples/Nested.psdeleted−3
@@ -1,3 +0,0 @@
1−data Extend r a = Extend { prev :: r a; next :: a }
2−
3−data Matrix r a = Square (r (r a)) | Bigger (Matrix (Extend r) a)
examples/Objects.psdeleted−9
@@ -1,9 +0,0 @@
1−test = \x -> x.foo + x.bar
2−
3−append = \o -> { foo: o.foo, bar: 1 }
4−
5−apTest = append({foo : "Foo", baz: "Baz"})
6−
7−f = (\a -> a.b.c) { b: { c: 1, d: "Hello" }, e: "World" }
8−
9−g = (\a -> a.f { x: 1, y: "y" }) { f: \o -> o.x + 1 }
examples/Operators.psdeleted−19
@@ -1,19 +0,0 @@
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))
6−
7−k = \x -> \y -> x
8−
9−test4 = 1 `k` 2
10−
11−(%%) = \x -> \y -> x * y + y
12−
13−test5 = 1 %% 2 %% 3
14−
15−test6 = ((\x -> x) `k` 2) 3
16−
17−(<>) = \s1 -> \s2 -> s1 ++ s2
18−
19−test7 = "Hello" <> "World!"
examples/Patterns.psdeleted−8
@@ -1,8 +0,0 @@
1−test = \x -> case x of
2− { str = "Foo", bool = true } -> true
3− { str = "Bar", bool = b } -> b
4− _ -> false
5−
6−f = \o -> case o of
7− { foo = "Foo" } -> o.bar
8− _ -> 0
examples/Person.psdeleted−7
@@ -1,7 +0,0 @@
1−data Person = Person { name :: String; age :: Number }
2−
3−extern itoa :: Number -> String
4−
5−showPerson :: Person -> String
6−showPerson = \p -> case p of
7− Person o -> o.name ++ ", aged " ++ itoa(o.age)
examples/ReadShow.psdeleted−5
@@ -1,5 +0,0 @@
1−extern read :: forall a. String -> a
2−
3−extern show :: forall a. a -> String
4−
5−test = \x -> show (read x)
examples/Recursion.psdeleted−4
@@ -1,4 +0,0 @@
1−fib = \n -> case n of
2− 0 -> 1
3− 1 -> 1
4− n -> fib (n - 1) + fib (n - 2)
examples/TypeDecl.psdeleted−12
@@ -1,12 +0,0 @@
1−id :: forall a. (a) -> a
2−id = \x -> x
3−
4−k :: String -> Number -> String
5−k = \x -> \y -> x
6−
7−iterate :: forall a. Number -> (a -> a) -> a -> a
8−iterate = \n -> \f -> \a -> do
9− var result = a
10− for i <- 0 until n:
11− result = f result
12− return result
examples/TypeSynonyms.psdeleted−13
@@ -1,13 +0,0 @@
1−type Lens a b =
2− { get :: a -> b
3− ; set :: a -> b -> b
4− }
5−
6−composeLenses :: forall a b c. Lens a b -> Lens b c -> Lens a c
7−composeLenses = \l1 -> \l2 ->
8− { get: \a -> l2.get (l1.get a)
9− , set: \a -> \c -> do
10− var b = l1.get a
11− var b1 = l2.set b c
12− return l1.set a b1
13− }
examples/iota.psdeleted−5
@@ -1,5 +0,0 @@
1−s = \x -> \y -> \z -> x z (y z)
2−
3−k = \x -> \y -> x
4−
5−iota = \x -> x s k
examples/runAll.testdeleted−23
@@ -1,23 +0,0 @@
1−# Maybe
2−mkdir -p tests && ../dist/build/psc/psc Maybe.ps -o tests/Maybe.js && cat tests/Maybe.js Maybe.js | node
3−<<<
4−>>>
5−{ ctor: 'Just', value: 'ab' }
6−>>>2
7−>>>= 0
8−
9−# List
10−mkdir -p tests && ../dist/build/psc/psc List.ps -o tests/List.js && cat tests/List.js List.js | node
11−<<<
12−>>>
13−[ 1, 2 ]
14−>>>2
15−>>>= 0
16−
17−# Foreach
18−mkdir -p tests && ../dist/build/psc/psc Foreach.ps -o tests/Foreach.js && cat tests/Foreach.js Foreach.js | node
19−<<<
20−>>>
21−15
22−>>>2
23−>>>= 0
examples/runMain.jsdeleted−1
@@ -1 +0,0 @@
1−main();
examples/s.psdeleted−1
@@ -1 +0,0 @@
1−s = \x, y, z -> x z (y z)
package.yamlnew file+86
@@ -0,0 +1,86 @@
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.cabalnew file+145
@@ -0,0 +1,145 @@
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.hsnew file+321
@@ -0,0 +1,321 @@
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.hsnew file+196
@@ -0,0 +1,196 @@
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.hsnew file+81
@@ -0,0 +1,81 @@
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.hsnew file+18
@@ -0,0 +1,18 @@
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.hsnew file+435
@@ -0,0 +1,435 @@
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.hsnew file+146
@@ -0,0 +1,146 @@
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.hsnew file+141
@@ -0,0 +1,141 @@
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.hsnew file+527
@@ -0,0 +1,527 @@
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.hsdeleted−73
@@ -1,73 +0,0 @@
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 Text.Parsec as P
24−import qualified System.IO.UTF8 as U
25−import qualified Data.Map as M
26−
27−compile :: [FilePath] -> Maybe FilePath -> Maybe FilePath -> IO ()
28−compile inputFiles outputFile externsFile = do
29− asts <- fmap (fmap concat . sequence) $ flip mapM inputFiles $ \inputFile -> do
30− text <- U.readFile inputFile
31− return $ runIndentParser 0 parseDeclarations text
32− case asts of
33− Left err -> do
34− U.print err
35− exitFailure
36− Right decls -> do
37− case check (typeCheckAll decls) of
38− Left typeError -> do
39− U.putStrLn typeError
40− exitFailure
41− Right (_, env) -> do
42− let js = intercalate "\n" $ mapMaybe declToJs decls
43− case outputFile of
44− Just path -> U.writeFile path js
45− Nothing -> U.putStrLn js
46− case externsFile of
47− Nothing -> return ()
48− Just filePath -> U.writeFile filePath $ intercalate "\n" $ mapMaybe (externToPs env) decls
49− exitSuccess
50−
51−inputFiles :: Term [FilePath]
52−inputFiles = nonEmpty $ posAny [] $ posInfo
53− { posDoc = "The input .ps files" }
54−
55−outputFile :: Term (Maybe FilePath)
56−outputFile = value $ opt Nothing $ (optInfo [ "o", "output" ])
57− { optDoc = "The output .js file" }
58−
59−externsFile :: Term (Maybe FilePath)
60−externsFile = value $ opt Nothing $ (optInfo [ "e", "externs" ])
61− { optDoc = "The output .e.ps file" }
62−
63−term :: Term (IO ())
64−term = compile <$> inputFiles <*> outputFile <*> externsFile
65−
66−termInfo :: TermInfo
67−termInfo = defTI
68− { termName = "psc"
69− , version = "1.0"
70− , termDoc = "Compiles PureScript to Javascript"
71− }
72−
73−main = run (term, termInfo)
src/PureScript.hsdeleted−33
@@ -1,33 +0,0 @@
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.Names,
21− module PureScript.Parser,
22− module PureScript.CodeGen,
23− module PureScript.TypeChecker
24−) where
25−
26−import PureScript.Values
27−import PureScript.Types
28−import PureScript.Kinds
29−import PureScript.Declarations
30−import PureScript.Names
31−import PureScript.Parser
32−import PureScript.CodeGen
33−import PureScript.TypeChecker
src/PureScript/CodeGen.hsdeleted−21
@@ -1,21 +0,0 @@
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−module PureScript.CodeGen (
16− module PureScript.CodeGen.JS,
17− module PureScript.CodeGen.Externs
18−) where
19−
20−import PureScript.CodeGen.JS
21−import PureScript.CodeGen.Externs
src/PureScript/CodeGen/Common.hsdeleted−80
@@ -1,80 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : PureScript.CodeGen.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−{-# LANGUAGE GeneralizedNewtypeDeriving, GADTs #-}
16−
17−module PureScript.CodeGen.Common where
18−
19−import Data.Char
20−import Data.Maybe (fromMaybe)
21−import Data.List (nub, intersperse, intercalate)
22−import Data.Function (fix)
23−import Control.Monad.State
24−import Control.Applicative (Applicative(..), Alternative(..))
25−import qualified Control.Category as C
26−import Control.Category ((>>>))
27−import qualified Control.Arrow as A
28−import Control.Arrow ((***), (<+>))
29−
30−import PureScript.Names
31−import PureScript.Values
32−import PureScript.Types
33−import PureScript.Declarations
34−
35−identToJs :: Ident -> String
36−identToJs (Ident name) = name
37−identToJs (Op op) = concatMap opCharToString op
38− where
39− opCharToString :: Char -> String
40− opCharToString = (:) '$'. show . ord
41−
42−newtype Pattern a b = Pattern { runPattern :: A.Kleisli Maybe a b } deriving (C.Category, A.Arrow, A.ArrowZero, A.ArrowPlus)
43−
44−instance Functor (Pattern a) where
45− fmap f (Pattern p) = Pattern $ A.Kleisli $ fmap f . A.runKleisli p
46−
47−pattern :: Pattern a b -> a -> Maybe b
48−pattern = A.runKleisli . runPattern
49−
50−parens :: String -> String
51−parens s = ('(':s) ++ ")"
52−
53−chainl :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r
54−chainl split f p = fix $ \c -> (split >>> ((c <+> p) *** p) >>> A.arr (uncurry f))
55−
56−chainr :: Pattern a (a, a) -> (r -> r -> r) -> Pattern a r -> Pattern a r
57−chainr split f p = fix $ \c -> (split >>> (p *** (c <+> p)) >>> A.arr (uncurry f))
58−
59−wrap :: Pattern a (s, a) -> (s -> r -> r) -> Pattern a r -> Pattern a r
60−wrap split f p = fix $ \c -> (split >>> (C.id *** (c <+> p)) >>> A.arr (uncurry f))
61−
62−split :: Pattern a (s, t) -> (s -> t -> r) -> Pattern a r -> Pattern a r
63−split s f p = (s >>> A.arr (uncurry f))
64−
65−data OperatorTable a r = OperatorTable { runOperatorTable :: [ [Operator a r] ] }
66−
67−data Operator a r where
68− AssocL :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r
69− AssocR :: Pattern a (a, a) -> (r -> r -> r) -> Operator a r
70− Wrap :: Pattern a (s, a) -> (s -> r -> r) -> Operator a r
71− Split :: Pattern a (s, t) -> (s -> t -> r) -> Operator a r
72−
73−buildPrettyPrinter :: OperatorTable a r -> Pattern a r -> Pattern a r
74−buildPrettyPrinter table p = foldl (\p' ops -> foldl1 (<+>) (flip map ops $ \op ->
75− case op of
76− AssocL pat g -> chainl pat g p'
77− AssocR pat g -> chainr pat g p'
78− Wrap pat g -> wrap pat g p'
79− Split pat g -> split pat g p'
80− ) <+> p') p $ runOperatorTable table
src/PureScript/CodeGen/Common/Gen.hsdeleted−31
@@ -1,31 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : PureScript.CodeGen.Common.Gen
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 #-}
16−
17−module PureScript.CodeGen.Common.Gen where
18−
19−import Control.Monad.State
20−import Control.Applicative
21−
22−newtype Gen a = Gen { unGen :: State Int a } deriving (Functor, Applicative, Monad, MonadState Int)
23−
24−runGen :: Gen a -> a
25−runGen = flip evalState 0 . unGen
26−
27−fresh :: Gen String
28−fresh = do
29− n <- get
30− modify (+ 1)
31− return $ "_" ++ show n
src/PureScript/CodeGen/Externs.hsdeleted−105
@@ -1,105 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : PureScript.CodeGen.Externs
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.Externs (
18− externToPs
19−) where
20−
21−import Data.Maybe (fromMaybe)
22−import Data.List (intersperse, intercalate)
23−import qualified Control.Arrow as A
24−import Control.Arrow ((<+>))
25−import qualified Data.Map as M
26−import Control.Applicative
27−
28−import PureScript.Values
29−import PureScript.Types
30−import PureScript.Names
31−import PureScript.Declarations
32−import PureScript.TypeChecker.Monad
33−import PureScript.CodeGen.Common
34−
35−externToPs :: Environment -> Declaration -> Maybe String
36−externToPs env (ValueDeclaration name _) = do
37− (ty, _) <- M.lookup name $ names env
38− return $ "extern " ++ show name ++ " :: " ++ polyTypeToPs ty
39−externToPs env (ExternDeclaration name ty) =
40− return $ "extern " ++ show name ++ " :: " ++ polyTypeToPs ty
41−externToPs env (TypeSynonymDeclaration name args ty) =
42− return $ "type " ++ name ++ " " ++ intercalate " " args ++ " = " ++ typeToPs ty
43−externToPs _ _ = Nothing
44−
45−typeLiterals :: Pattern Type String
46−typeLiterals = Pattern $ A.Kleisli match
47− where
48− match Number = Just "Number"
49− match String = Just "String"
50− match Boolean = Just "Boolean"
51− match (Array ty) = Just $ "[" ++ typeToPs ty ++ "]"
52− match (Object row) = Just $ "{ " ++ rowToPs row ++ " }"
53− match (TypeVar var) = Just var
54− match (TypeConstructor ctor) = Just ctor
55− match (TUnknown u) = Just $ show u
56− match _ = Nothing
57−
58−rowToPs :: Row -> String
59−rowToPs = (\(tys, tail) -> intercalate "; " (map (uncurry nameAndTypeToPs) tys) ++ tailToPs tail) . toList
60− where
61− nameAndTypeToPs :: String -> Type -> String
62− nameAndTypeToPs name ty = name ++ " :: " ++ typeToPs ty
63− tailToPs :: Row -> String
64− tailToPs REmpty = ""
65− tailToPs (RUnknown u) = show u
66− tailToPs (RowVar var) = " | " ++ var
67− toList :: Row -> ([(String, Type)], Row)
68− toList (RCons name ty row) = let (tys, rest) = toList row
69− in ((name, ty):tys, rest)
70− toList r = ([], r)
71−
72−typeApp :: Pattern Type (Type, Type)
73−typeApp = Pattern $ A.Kleisli match
74− where
75− match (TypeApp f x) = Just (f, x)
76− match _ = Nothing
77−
78−singleArgumentFunction :: Pattern Type (Type, Type)
79−singleArgumentFunction = Pattern $ A.Kleisli match
80− where
81− match (Function [arg] ret) = Just (arg, ret)
82− match _ = Nothing
83−
84−function :: Pattern Type ([Type], Type)
85−function = Pattern $ A.Kleisli match
86− where
87− match (Function args ret) = Just (args, ret)
88− match _ = Nothing
89−
90−typeToPs :: Type -> String
91−typeToPs = fromMaybe (error "Incomplete pattern") . pattern matchType
92− where
93− matchType :: Pattern Type String
94− matchType = buildPrettyPrinter operators (typeLiterals <+> fmap parens matchType)
95− operators :: OperatorTable Type String
96− operators =
97− OperatorTable $ [ [ AssocL typeApp $ \f x -> f ++ " " ++ x ]
98− , [ AssocR singleArgumentFunction $ \arg ret -> arg ++ " -> " ++ ret
99− , Wrap function $ \args ret -> "(" ++ intercalate ", " (map typeToPs args) ++ ") -> " ++ ret
100− ]
101− ]
102−
103−polyTypeToPs :: PolyType -> String
104−polyTypeToPs (PolyType [] ty) = typeToPs ty
105−polyTypeToPs (PolyType idents ty) = "forall " ++ intercalate " " idents ++ ". " ++ typeToPs ty
src/PureScript/CodeGen/JS.hsdeleted−260
@@ -1,260 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : PureScript.CodeGen.JS
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.CodeGen.JS (
16− declToJs
17−) where
18−
19−import Data.Char
20−import Data.Maybe (fromMaybe)
21−import Data.List (intercalate)
22−import qualified Control.Arrow as A
23−import Control.Arrow ((<+>))
24−import Control.Applicative
25−
26−import PureScript.Types
27−import PureScript.Values
28−import PureScript.Names
29−import PureScript.Declarations
30−import PureScript.CodeGen.Common
31−import PureScript.CodeGen.Common.Gen
32−
33−declToJs :: Declaration -> Maybe String
34−declToJs (ValueDeclaration ident (Abs args ret)) = Just $ "function " ++ identToJs ident ++ "(" ++ intercalate "," (map identToJs args) ++ ") { return " ++ valueToJs ret ++ "; }"
35−declToJs (ValueDeclaration ident val) = Just $ "var " ++ identToJs ident ++ " = " ++ valueToJs val ++ ";"
36−declToJs (DataDeclaration _ _ ctors) =
37− Just $ flip concatMap ctors $ \(ctor, maybeTy) ->
38− case maybeTy of
39− Nothing -> "var " ++ ctor ++ " = { ctor: '" ++ ctor ++ "' };"
40− Just _ -> "var " ++ ctor ++ " = function (value) { return { ctor: '" ++ ctor ++ "', value: value }; };"
41−declToJs _ = Nothing
42−
43−literals :: Pattern Value String
44−literals = Pattern $ A.Kleisli match
45− where
46− match (NumericLiteral n) = Just $ either show show n
47− match (StringLiteral s) = Just $ show s
48− match (BooleanLiteral True) = Just "true"
49− match (BooleanLiteral False) = Just "false"
50− match (ArrayLiteral xs) = Just $ "[" ++ intercalate "," (map valueToJs xs) ++ "]"
51− match (ObjectLiteral ps) = Just $ "{" ++ intercalate "," (map objectPropertyToJs ps) ++ "}"
52− match (Constructor name) = Just name
53− match (Block sts) = Just $ "(function () {" ++ intercalate ";" (map statementToJs sts) ++ "})()"
54− match (Case value binders) = Just $ "(" ++ runGen (bindersToJs binders) ++ ")(" ++ valueToJs value ++ ")"
55− where
56− bindersToJs :: [(Binder, Value)] -> Gen String
57− bindersToJs binders = do
58− valName <- fresh
59− jss <- flip mapM binders $ \(binder, result) -> do
60− let js = valueToJs result
61− binderToJs valName ("return " ++ js ++ ";") binder
62− return $ "function (" ++ valName ++ ") {" ++ concat jss ++ "throw \"Failed pattern match\"; }"
63− match (Var ident) = Just (identToJs ident)
64− match _ = Nothing
65−
66−ifThenElse :: Pattern Value ((Value, Value), Value)
67−ifThenElse = Pattern $ A.Kleisli match
68− where
69− match (IfThenElse cond th el) = Just ((th, el), cond)
70− match _ = Nothing
71−
72−accessor :: Pattern Value (String, Value)
73−accessor = Pattern $ A.Kleisli match
74− where
75− match (Accessor prop val) = Just (prop, val)
76− match _ = Nothing
77−
78−indexer :: Pattern Value (String, Value)
79−indexer = Pattern $ A.Kleisli match
80− where
81− match (Indexer index val) = Just (valueToJs index, val)
82− match _ = Nothing
83−
84−app :: Pattern Value (String, Value)
85−app = Pattern $ A.Kleisli match
86− where
87− match (App val args) = Just (intercalate "," (map valueToJs args), val)
88− match _ = Nothing
89−
90−lam :: Pattern Value ([String], Value)
91−lam = Pattern $ A.Kleisli match
92− where
93− match (Abs args val) = Just (map identToJs args, val)
94− match _ = Nothing
95−
96−unary :: UnaryOperator -> String -> Operator Value String
97−unary op str = Wrap pattern (++)
98− where
99− pattern :: Pattern Value (String, Value)
100− pattern = Pattern $ A.Kleisli match
101− where
102− match (Unary op' val) | op' == op = Just (str, val)
103− match _ = Nothing
104−
105−binary :: BinaryOperator -> String -> Operator Value String
106−binary op str = AssocR pattern (\v1 v2 -> v1 ++ " " ++ str ++ " " ++ v2)
107− where
108− pattern :: Pattern Value (Value, Value)
109− pattern = Pattern $ A.Kleisli match
110− where
111− match (Binary op' v1 v2) | op' == op = Just (v1, v2)
112− match _ = Nothing
113−
114−valueToJs :: Value -> String
115−valueToJs = fromMaybe (error "Incomplete pattern") . pattern matchValue
116− where
117− matchValue :: Pattern Value String
118− matchValue = buildPrettyPrinter operators (literals <+> fmap parens matchValue)
119− operators :: OperatorTable Value String
120− operators =
121− OperatorTable $ [ [ Wrap accessor $ \prop val -> val ++ "." ++ prop ]
122− , [ Wrap indexer $ \index val -> val ++ "[" ++ index ++ "]" ]
123− , [ Wrap app $ \args val -> val ++ "(" ++ args ++ ")" ]
124− , [ Split lam $ \args val -> "function (" ++ intercalate "," args ++ ") { return " ++ valueToJs val ++ "; }" ]
125− , [ Wrap ifThenElse $ \(th, el) cond -> cond ++ " ? " ++ valueToJs th ++ " : " ++ valueToJs el ]
126− , [ binary LessThan "<" ]
127− , [ binary LessThanOrEqualTo "<=" ]
128− , [ binary GreaterThan ">" ]
129− , [ binary GreaterThanOrEqualTo ">=" ]
130− , [ unary Not "!" ]
131− , [ unary BitwiseNot "~" ]
132− , [ unary Negate "-" ]
133− , [ binary Multiply "*" ]
134− , [ binary Divide "/" ]
135− , [ binary Modulus "%" ]
136− , [ binary Concat "+" ]
137− , [ binary Add "+" ]
138− , [ binary Subtract "-" ]
139− , [ binary ShiftLeft "<<" ]
140− , [ binary ShiftRight ">>" ]
141− , [ binary ZeroFillShiftRight ">>>" ]
142− , [ binary EqualTo "===" ]
143− , [ binary NotEqualTo "!==" ]
144− , [ binary BitwiseAnd "&" ]
145− , [ binary BitwiseXor "^" ]
146− , [ binary BitwiseOr "|" ]
147− , [ binary And "&&" ]
148− , [ binary Or "||" ]
149− ]
150−
151−unaryOperatorString :: UnaryOperator -> String
152−unaryOperatorString Negate = "-"
153−unaryOperatorString Not = "!"
154−unaryOperatorString BitwiseNot = "~"
155−
156−binaryOperatorString :: BinaryOperator -> String
157−binaryOperatorString Add = "+"
158−binaryOperatorString Subtract = "-"
159−binaryOperatorString Multiply = "*"
160−binaryOperatorString Divide = "/"
161−binaryOperatorString Modulus = "%"
162−binaryOperatorString LessThan = "<"
163−binaryOperatorString LessThanOrEqualTo = "<="
164−binaryOperatorString GreaterThan = ">"
165−binaryOperatorString GreaterThanOrEqualTo = ">="
166−binaryOperatorString BitwiseAnd = "&"
167−binaryOperatorString BitwiseOr = "|"
168−binaryOperatorString BitwiseXor = "^"
169−binaryOperatorString ShiftLeft = "<<"
170−binaryOperatorString ShiftRight = ">>"
171−binaryOperatorString ZeroFillShiftRight = ">>>"
172−binaryOperatorString EqualTo = "==="
173−binaryOperatorString NotEqualTo = "!=="
174−binaryOperatorString And = "&&"
175−binaryOperatorString Or = "||"
176−binaryOperatorString Concat = "+"
177−
178−binderToJs :: String -> String -> Binder -> Gen String
179−binderToJs varName done NullBinder = return done
180−binderToJs varName done (StringBinder str) =
181− return $ "if (" ++ varName ++ " === \"" ++ str ++ "\") {" ++ done ++ " }"
182−binderToJs varName done (NumberBinder num) =
183− return $ "if (" ++ varName ++ " === " ++ either show show num ++ ") {" ++ done ++ " }"
184−binderToJs varName done (BooleanBinder True) =
185− return $ "if (" ++ varName ++ ") {" ++ done ++ " }"
186−binderToJs varName done (BooleanBinder False) =
187− return $ "if (!" ++ varName ++ ") {" ++ done ++ " }"
188−binderToJs varName done (VarBinder ident) =
189− return $ "var " ++ identToJs ident ++ " = " ++ varName ++ "; " ++ done
190−binderToJs varName done (NullaryBinder ctor) =
191− return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ done ++ " }"
192−binderToJs varName done (UnaryBinder ctor b) = do
193− value <- fresh
194− js <- binderToJs value done b
195− return $ "if (" ++ varName ++ ".ctor === \"" ++ ctor ++ "\") { " ++ "var " ++ value ++ " = " ++ varName ++ ".value; " ++ js ++ " }"
196−binderToJs varName done (ObjectBinder bs) = go done bs
197− where
198− go done [] = return done
199− go done ((prop, binder):bs) = do
200− propVar <- fresh
201− done' <- go done bs
202− js <- binderToJs propVar done' binder
203− return $ "var " ++ propVar ++ " = " ++ varName ++ "." ++ prop ++ ";" ++ js
204−binderToJs varName done (ArrayBinder bs rest) = do
205− js <- go done rest 0 bs
206− return $ "if (" ++ varName ++ ".length " ++ cmp ++ " " ++ show (length bs) ++ ") { " ++ js ++ " }"
207− where
208− cmp = maybe "===" (const ">=") rest
209− go done Nothing _ [] = return done
210− go done (Just binder) index [] = do
211− restVar <- fresh
212− js <- binderToJs restVar done binder
213− return $ "var " ++ restVar ++ " = " ++ varName ++ ".slice(" ++ show index ++ "); " ++ js
214− go done rest index (binder:bs) = do
215− elVar <- fresh
216− done' <- go done rest (index + 1) bs
217− js <- binderToJs elVar done' binder
218− return $ "var " ++ elVar ++ " = " ++ varName ++ "[" ++ show index ++ "]; " ++ js
219−binderToJs varName done (NamedBinder ident binder) = do
220− js <- binderToJs varName done binder
221− return $ "var " ++ identToJs ident ++ " = " ++ varName ++ "; " ++ js
222−binderToJs varName done (GuardedBinder cond binder) = binderToJs varName done' binder
223− where
224− done' = "if (" ++ valueToJs cond ++ ") { " ++ done ++ "}"
225−
226−objectPropertyToJs :: (String, Value) -> String
227−objectPropertyToJs (key, value) = key ++ ":" ++ valueToJs value
228−
229−statementToJs :: Statement -> String
230−statementToJs (VariableIntroduction ident value) = "var " ++ identToJs ident ++ " = " ++ valueToJs value
231−statementToJs (Assignment target value) = assignmentTargetToJs target ++ " = " ++ valueToJs value
232−statementToJs (While cond sts) = "while ("
233− ++ valueToJs cond ++ ") {"
234− ++ intercalate ";" (map statementToJs sts) ++ "}"
235−statementToJs (For ident start end sts) = "for (" ++
236− identToJs ident ++ " = " ++ valueToJs start ++ ";"
237− ++ identToJs ident ++ " < " ++ valueToJs end ++ ";"
238− ++ identToJs ident ++ "++) {"
239− ++ intercalate ";" (map statementToJs sts) ++ "}"
240−statementToJs (ForEach ident arr sts) = valueToJs arr
241− ++ ".forEach(function(" ++ identToJs ident ++ ") {"
242− ++ intercalate ";" (map statementToJs sts) ++ "})"
243−statementToJs (If ifst) = ifStatementToJs ifst
244−statementToJs (Return value) = "return " ++ valueToJs value
245−
246−ifStatementToJs :: IfStatement -> String
247−ifStatementToJs (IfStatement cond thens elst) =
248− "if ("
249− ++ valueToJs cond ++ ") {"
250− ++ intercalate ";" (map statementToJs thens) ++ "}"
251− ++ maybe "" elseStatementToJs elst
252−
253−elseStatementToJs :: ElseStatement -> String
254−elseStatementToJs (Else sts) = " else {" ++ intercalate ";" (map statementToJs sts) ++ "}"
255−elseStatementToJs (ElseIf ifst) = " else " ++ ifStatementToJs ifst
256−
257−assignmentTargetToJs :: AssignmentTarget -> String
258−assignmentTargetToJs (AssignVariable ident) = identToJs ident
259−assignmentTargetToJs (AssignArrayIndex index tgt) = assignmentTargetToJs tgt ++ "[" ++ valueToJs index ++ "]"
260−assignmentTargetToJs (AssignObjectProperty prop tgt) = assignmentTargetToJs tgt ++ "." ++ prop
src/PureScript/Declarations.hsdeleted−30
@@ -1,30 +0,0 @@
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−{-# LANGUAGE DeriveDataTypeable #-}
16−
17−module PureScript.Declarations where
18−
19−import PureScript.Values
20−import PureScript.Types
21−import PureScript.Names
22−
23−import Data.Data
24−
25−data Declaration
26− = DataDeclaration String [String] [(String, Maybe Type)]
27− | TypeSynonymDeclaration String [String] Type
28− | TypeDeclaration Ident PolyType
29− | ValueDeclaration Ident Value
30− | ExternDeclaration Ident PolyType deriving (Show, Data, Typeable)
src/PureScript/Kinds.hsdeleted−25
@@ -1,25 +0,0 @@
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−{-# LANGUAGE DeriveDataTypeable #-}
16−
17−module PureScript.Kinds where
18−
19−import Data.Data
20−
21−data Kind
22− = KUnknown Int
23− | Star
24− | Row
25− | FunKind Kind Kind deriving (Show, Eq, Data, Typeable)
src/PureScript/Names.hsdeleted−26
@@ -1,26 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : PureScript.Names
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 DeriveDataTypeable #-}
16−
17−module PureScript.Names where
18−
19−import Data.Data
20−
21−data Ident = Ident String | Op String deriving (Eq, Ord, Data, Typeable)
22−
23−instance Show Ident where
24− show (Ident s) = s
25− show (Op op) = '(':op ++ ")"
26−
src/PureScript/Parser.hsdeleted−26
@@ -1,26 +0,0 @@
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.Common,
17− module PureScript.Parser.Types,
18− module PureScript.Parser.Values,
19− module PureScript.Parser.Declarations
20−) where
21−
22−import PureScript.Parser.Common
23−import PureScript.Parser.Types
24−import PureScript.Parser.Values
25−import PureScript.Parser.Declarations
26−
src/PureScript/Parser/Common.hsdeleted−176
@@ -1,176 +0,0 @@
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−{-# LANGUAGE FlexibleContexts #-}
16−
17−module PureScript.Parser.Common where
18−
19−import Data.Char (isSpace)
20−import Control.Applicative
21−import Control.Monad
22−import Control.Monad.State
23−import qualified Text.Parsec as P
24−import qualified Text.Parsec.Pos as P
25−import qualified Text.Parsec.Token as PT
26−
27−import PureScript.Names
28−
29−reservedNames :: [String]
30−reservedNames = [ "case"
31− , "of"
32− , "data"
33− , "type"
34− , "var"
35− , "val"
36− , "while"
37− , "for"
38− , "foreach"
39− , "if"
40− , "then"
41− , "else"
42− , "return"
43− , "true"
44− , "false"
45− , "extern"
46− , "forall"
47− , "do"
48− , "until"
49− , "in"
50− , "break"
51− , "catch"
52− , "continue"
53− , "debugger"
54− , "default"
55− , "delete"
56− , "finally"
57− , "function"
58− , "instanceof"
59− , "new"
60− , "switch"
61− , "this"
62− , "throw"
63− , "try"
64− , "typeof"
65− , "void"
66− , "with"
67− , "Number"
68− , "String"
69− , "Boolean" ]
70−
71−reservedOpNames :: [String]
72−reservedOpNames = [ "!", "~", "-", "<=", ">=", "<", ">", "*", "/", "%", "++", "+", "<<", ">>>", ">>"
73− , "==", "!=", "&", "^", "|", "&&", "||", "->" ]
74−
75−identStart :: P.Parsec String u Char
76−identStart = P.lower <|> P.oneOf "_$"
77−
78−properNameStart :: P.Parsec String u Char
79−properNameStart = P.upper
80−
81−identLetter :: P.Parsec String u Char
82−identLetter = P.alphaNum <|> P.oneOf "_'"
83−
84−opStart :: P.Parsec String u Char
85−opStart = P.oneOf "!#$%&*+/<=>?@^|-~"
86−
87−opLetter :: P.Parsec String u Char
88−opLetter = P.oneOf ":#$%&*+./<=>?@^|"
89−
90−langDef = PT.LanguageDef
91− { PT.reservedNames = reservedNames
92− , PT.reservedOpNames = reservedOpNames
93− , PT.commentStart = "{-"
94− , PT.commentEnd = "-}"
95− , PT.commentLine = "--"
96− , PT.nestedComments = True
97− , PT.identStart = identStart
98− , PT.identLetter = identLetter
99− , PT.opStart = opStart
100− , PT.opLetter = opLetter
101− , PT.caseSensitive = True
102− }
103−
104−tokenParser = PT.makeTokenParser langDef
105−
106−lexeme = PT.lexeme tokenParser
107−identifier = PT.identifier tokenParser
108−reserved = PT.reserved tokenParser
109−reservedOp = PT.reservedOp tokenParser
110−operator = PT.operator tokenParser
111−stringLiteral = PT.stringLiteral tokenParser
112−whiteSpace = PT.whiteSpace tokenParser
113−parens = PT.parens tokenParser
114−braces = PT.braces tokenParser
115−angles = PT.angles tokenParser
116−squares = PT.squares tokenParser
117−semi = PT.semi tokenParser
118−comma = PT.comma tokenParser
119−colon = PT.colon tokenParser
120−dot = PT.dot tokenParser
121−semiSep = PT.semiSep tokenParser
122−semiSep1 = PT.semiSep1 tokenParser
123−commaSep = PT.commaSep tokenParser
124−commaSep1 = PT.commaSep1 tokenParser
125−
126−tick :: P.Parsec String u Char
127−tick = lexeme $ P.char '`'
128−
129−properName :: P.Parsec String u String
130−properName = lexeme $ P.try ((:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name")
131−
132−integerOrFloat :: P.Parsec String u (Either Integer Double)
133−integerOrFloat = Left <$> P.try (PT.natural tokenParser) <|>
134− Right <$> P.try (PT.float tokenParser)
135−
136−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
137−augment p q f = (flip $ maybe id $ flip f) <$> p <*> P.optionMaybe q
138−
139−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
140−fold first more combine = do
141− a <- first
142− bs <- P.many more
143− return $ foldl combine a bs
144−
145−buildPostfixParser :: P.Stream s m t => [P.ParsecT s u m (a -> a)] -> P.ParsecT s u m a -> P.ParsecT s u m a
146−buildPostfixParser f x = fold x (P.choice (map P.try f)) (flip ($))
147−
148−parseIdent :: P.Parsec String u Ident
149−parseIdent = (Ident <$> identifier) <|> (Op <$> parens operator)
150−
151−parseIdentInfix :: P.Parsec String u Ident
152−parseIdentInfix = (Ident <$> P.between tick tick identifier) <|> (Op <$> operator)
153−
154−mark :: P.Parsec String P.Column a -> P.Parsec String P.Column a
155−mark p = do
156− current <- P.getState
157− pos <- P.sourceColumn <$> P.getPosition
158− P.putState pos
159− a <- p
160− P.putState current
161− return a
162−
163−checkIndentation :: (P.Column -> P.Column -> Bool) -> P.Parsec String P.Column ()
164−checkIndentation rel = (do
165− col <- P.sourceColumn <$> P.getPosition
166− current <- P.getState
167− guard $ col `rel` current) <|> P.parserFail "Indentation check"
168−
169−indented :: P.Parsec String P.Column ()
170−indented = checkIndentation (>)
171−
172−same :: P.Parsec String P.Column ()
173−same = checkIndentation (==)
174−
175−runIndentParser :: P.Column -> P.Parsec String P.Column a -> String -> Either P.ParseError a
176−runIndentParser col p = P.runParser p 0 ""
src/PureScript/Parser/Declarations.hsdeleted−76
@@ -1,76 +0,0 @@
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.Maybe
23−import Data.Function
24−import Control.Applicative
25−import Control.Arrow (Arrow(..))
26−import Control.Monad.State
27−import qualified Text.Parsec as P
28−import qualified Text.Parsec.Pos as P
29−
30−import PureScript.Values
31−import PureScript.Types
32−import PureScript.Parser.Common
33−import PureScript.Declarations
34−import PureScript.Parser.Values
35−import PureScript.Parser.Types
36−
37−parseDataDeclaration :: P.Parsec String P.Column Declaration
38−parseDataDeclaration = do
39− reserved "data"
40− name <- indented *> properName
41− tyArgs <- many (indented *> identifier)
42− lexeme $ indented *> P.char '='
43− ctors <- P.sepBy1 ((,) <$> (indented *> properName) <*> P.optionMaybe parseType) (lexeme $ indented *> P.char '|')
44− return $ DataDeclaration name tyArgs ctors
45−
46−parseTypeDeclaration :: P.Parsec String P.Column Declaration
47−parseTypeDeclaration =
48− TypeDeclaration <$> parseIdent
49− <*> (lexeme (indented *> P.string "::") *> parsePolyType)
50−
51−parseTypeSynonymDeclaration :: P.Parsec String P.Column Declaration
52−parseTypeSynonymDeclaration =
53− TypeSynonymDeclaration <$> (reserved "type" *> indented *> properName)
54− <*> many (indented *> identifier)
55− <*> (lexeme (indented *> P.char '=') *> parseType)
56−
57−parseValueDeclaration :: P.Parsec String P.Column Declaration
58−parseValueDeclaration =
59− ValueDeclaration <$> parseIdent
60− <*> (lexeme (indented *> P.char '=') *> parseValue)
61−
62−parseExternDeclaration :: P.Parsec String P.Column Declaration
63−parseExternDeclaration =
64− ExternDeclaration <$> (reserved "extern" *> indented *> parseIdent)
65− <*> (lexeme (indented *> P.string "::") *> parsePolyType)
66−
67−parseDeclaration :: P.Parsec String P.Column Declaration
68−parseDeclaration = P.choice $ map P.try
69− [ parseDataDeclaration
70− , parseTypeDeclaration
71− , parseTypeSynonymDeclaration
72− , parseValueDeclaration
73− , parseExternDeclaration ]
74−
75−parseDeclarations :: P.Parsec String P.Column [Declaration]
76−parseDeclarations = whiteSpace *> mark (same *> P.many parseDeclaration) <* P.eof
src/PureScript/Parser/Types.hsdeleted−90
@@ -1,90 +0,0 @@
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− parsePolyType,
18− parseRow
19−) where
20−
21−import PureScript.Types
22−import PureScript.Parser.Common
23−import Control.Applicative
24−import qualified Text.Parsec as P
25−import qualified Text.Parsec.Expr as P
26−import Control.Arrow (Arrow(..))
27−
28−parseNumber :: P.Parsec String P.Column Type
29−parseNumber = const Number <$> reserved "Number"
30−
31−parseString :: P.Parsec String P.Column Type
32−parseString = const String <$> reserved "String"
33−
34−parseBoolean :: P.Parsec String P.Column Type
35−parseBoolean = const Boolean <$> reserved "Boolean"
36−
37−parseArray :: P.Parsec String P.Column Type
38−parseArray = squares $ Array <$> parseType
39−
40−parseObject :: P.Parsec String P.Column Type
41−parseObject = braces $ Object <$> parseRow
42−
43−parseFunction :: P.Parsec String P.Column Type
44−parseFunction = do
45− args <- lexeme $ parens $ commaSep parseType
46− lexeme $ P.string "->"
47− resultType <- parseType
48− return $ Function args resultType
49−
50−parseTypeVariable :: P.Parsec String P.Column Type
51−parseTypeVariable = TypeVar <$> identifier
52−
53−parseTypeConstructor :: P.Parsec String P.Column Type
54−parseTypeConstructor = TypeConstructor <$> properName
55−
56−parseTypeAtom :: P.Parsec String P.Column Type
57−parseTypeAtom = indented *> P.choice (map P.try
58− [ parseNumber
59− , parseString
60− , parseBoolean
61− , parseArray
62− , parseObject
63− , parseFunction
64− , parseTypeVariable
65− , parseTypeConstructor
66− , parens parseType ])
67−
68−parsePolyType :: P.Parsec String P.Column PolyType
69−parsePolyType = PolyType <$> (P.option [] (indented *> reserved "forall" *> many (indented *> identifier) <* indented <* dot))
70− <*> parseType
71−
72−parseType :: P.Parsec String P.Column Type
73−parseType = P.buildExpressionParser operators . buildPostfixParser postfixTable $ parseTypeAtom
74− where
75− postfixTable :: [P.Parsec String P.Column (Type -> Type)]
76− postfixTable = [ flip TypeApp <$> (indented *> parseTypeAtom) ]
77− operators = [ [ P.Infix (lexeme (P.try (P.string "->")) >> return (\t1 t2 -> Function [t1] t2)) P.AssocRight ] ]
78−
79−parseNameAndType :: P.Parsec String P.Column (String, Type)
80−parseNameAndType = (,) <$> (indented *> identifier <* indented <* lexeme (P.string "::")) <*> parseType
81−
82−parseRowEnding :: P.Parsec String P.Column Row
83−parseRowEnding = P.option REmpty (RowVar <$> (lexeme (indented *> P.char '|') *> indented *> identifier))
84−
85−parseRow :: P.Parsec String P.Column Row
86−parseRow = fromList <$> (parseNameAndType `P.sepBy` (indented *> semi)) <*> parseRowEnding
87− where
88− fromList :: [(String, Type)] -> Row -> Row
89− fromList [] r = r
90− fromList ((name, t):ts) r = RCons name t (fromList ts r)
src/PureScript/Parser/Values.hsdeleted−255
@@ -1,255 +0,0 @@
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 P.Column Bool
31−booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)
32−
33−parseNumericLiteral :: P.Parsec String P.Column Value
34−parseNumericLiteral = NumericLiteral <$> C.integerOrFloat
35−
36−parseStringLiteral :: P.Parsec String P.Column Value
37−parseStringLiteral = StringLiteral <$> C.stringLiteral
38−
39−parseBooleanLiteral :: P.Parsec String P.Column Value
40−parseBooleanLiteral = BooleanLiteral <$> booleanLiteral
41−
42−parseArrayLiteral :: P.Parsec String P.Column Value
43−parseArrayLiteral = ArrayLiteral <$> (C.squares $ parseValue `P.sepBy` (C.indented *> C.comma))
44−
45−parseObjectLiteral :: P.Parsec String P.Column Value
46−parseObjectLiteral = ObjectLiteral <$> (C.braces $ parseIdentifierAndValue `P.sepBy` (C.indented *> C.comma))
47−
48−parseIdentifierAndValue :: P.Parsec String P.Column (String, Value)
49−parseIdentifierAndValue = (,) <$> (C.indented *> C.identifier <* C.indented <* C.colon)
50− <*> (C.indented *> parseValue)
51−
52−parseAbs :: P.Parsec String P.Column Value
53−parseAbs = do
54− C.lexeme $ P.char '\\'
55− args <- (C.indented *> C.parseIdent) `P.sepBy` (C.indented *> C.comma)
56− C.lexeme $ C.indented *> P.string "->"
57− value <- parseValue
58− return $ Abs args value
59−
60−parseApp :: P.Parsec String P.Column Value
61−parseApp = App <$> parseValue
62− <*> (C.indented *> C.parens (parseValue `P.sepBy` (C.indented *> C.comma)))
63−
64−parseVar :: P.Parsec String P.Column Value
65−parseVar = Var <$> C.parseIdent
66−
67−parseConstructor :: P.Parsec String P.Column Value
68−parseConstructor = Constructor <$> C.properName
69−
70−parseCase :: P.Parsec String P.Column Value
71−parseCase = Case <$> (P.between (C.reserved "case") (C.indented *> C.reserved "of") parseValue)
72− <*> (C.indented *> C.mark (P.many (C.same *> C.mark parseCaseAlternative)))
73−
74−parseCaseAlternative :: P.Parsec String P.Column (Binder, Value)
75−parseCaseAlternative = (,) <$> (parseGuardedBinder <* C.lexeme (P.string "->")) <*> parseValue
76−
77−parseIfThenElse :: P.Parsec String P.Column Value
78−parseIfThenElse = IfThenElse <$> (C.reserved "if" *> C.indented *> parseValue)
79− <*> (C.indented *> C.reserved "then" *> C.indented *> parseValue)
80− <*> (C.indented *> C.reserved "else" *> C.indented *> parseValue)
81−
82−parseBlock :: P.Parsec String P.Column Value
83−parseBlock = Block <$> (C.reserved "do" *> parseManyStatements)
84−
85−parseManyStatements :: P.Parsec String P.Column [Statement]
86−parseManyStatements = C.indented *> (C.mark $ P.many $ C.same *> C.mark parseStatement)
87−
88−parseValueAtom :: P.Parsec String P.Column Value
89−parseValueAtom = C.indented *> P.choice (map P.try
90− [ parseNumericLiteral
91− , parseStringLiteral
92− , parseBooleanLiteral
93− , parseArrayLiteral
94− , parseObjectLiteral
95− , parseAbs
96− , parseVar
97− , parseConstructor
98− , parseBlock
99− , parseCase
100− , parseIfThenElse
101− , C.parens parseValue ])
102−
103−parseValue :: P.Parsec String P.Column Value
104−parseValue = buildExpressionParser operators . C.buildPostfixParser postfixTable2 $ indexersAndAccessors
105− where
106− indexersAndAccessors = C.buildPostfixParser postfixTable1 $ parseValueAtom
107− postfixTable1 = [ Accessor <$> (C.indented *> C.dot *> C.indented *> C.identifier)
108− , Indexer <$> (C.indented *> C.squares parseValue) ]
109− postfixTable2 = [ C.indented *> indexersAndAccessors >>= \t2 -> return (\t1 -> App t1 [t2])
110− , flip App <$> (C.indented *> C.parens (parseValue `P.sepBy` (C.indented *> C.comma)))
111− , flip TypedValue <$> (P.try $ C.lexeme (C.indented *> P.string "::") *> parsePolyType) ]
112− operators = [ [ Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "!") >> return (Unary Not)
113− , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "~") >> return (Unary BitwiseNot)
114− , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "-") >> return (Unary Negate)
115− , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "+") >> return id ]
116− , [ Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix) >>= \ident -> return $ \t1 t2 -> App (App (Var ident) [t1]) [t2])) AssocRight ]
117− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<=") >> return (Binary LessThanOrEqualTo)) AssocRight
118− , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">=") >> return (Binary GreaterThanOrEqualTo)) AssocRight ]
119− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<") >> return (Binary LessThan)) AssocRight
120− , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">") >> return (Binary GreaterThan)) AssocRight ]
121− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "*") >> return (Binary Multiply)) AssocRight
122− , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "/") >> return (Binary Divide)) AssocRight
123− , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "%") >> return (Binary Modulus)) AssocRight ]
124− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "++") >> return (Binary Concat)) AssocRight
125− , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "+") >> return (Binary Add)) AssocRight
126− , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "-") >> return (Binary Subtract)) AssocRight ]
127− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<<") >> return (Binary ShiftLeft)) AssocRight
128− , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">>>") >> return (Binary ZeroFillShiftRight)) AssocRight
129− , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">>") >> return (Binary ShiftRight)) AssocRight ]
130− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "==") >> return (Binary EqualTo)) AssocRight
131− , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "!=") >> return (Binary NotEqualTo)) AssocRight ]
132− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "&") >> return (Binary BitwiseAnd)) AssocRight ]
133− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "^") >> return (Binary BitwiseXor)) AssocRight ]
134− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "|") >> return (Binary BitwiseOr)) AssocRight ]
135− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "&&") >> return (Binary And)) AssocRight ]
136− , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "||") >> return (Binary Or)) AssocRight ]
137− ]
138−
139−parseVariableIntroduction :: P.Parsec String P.Column Statement
140−parseVariableIntroduction = do
141− C.reserved "var"
142− name <- C.indented *> C.parseIdent
143− C.lexeme $ C.indented *> P.char '='
144− value <- parseValue
145− return $ VariableIntroduction name value
146−
147−parseAssignment :: P.Parsec String P.Column Statement
148−parseAssignment = do
149− tgt <- parseAssignmentTarget
150− C.lexeme $ C.indented *> P.char '='
151− value <- parseValue
152− return $ Assignment tgt value
153−
154−parseWhile :: P.Parsec String P.Column Statement
155−parseWhile = While <$> (C.reserved "while" *> C.indented *> parseValue <* C.indented <* C.colon)
156− <*> parseManyStatements
157−
158−parseFor :: P.Parsec String P.Column Statement
159−parseFor = For <$> (C.reserved "for" *> C.indented *> C.parseIdent)
160− <*> (C.indented *> C.lexeme (P.string "<-") *> parseValue)
161− <*> (C.indented *> C.reserved "until" *> parseValue <* C.colon)
162− <*> parseManyStatements
163−
164−parseForEach :: P.Parsec String P.Column Statement
165−parseForEach = ForEach <$> (C.reserved "foreach" *> C.indented *> C.parseIdent)
166− <*> (C.indented *> C.reserved "in" *> parseValue <* C.colon)
167− <*> parseManyStatements
168−
169−parseIf :: P.Parsec String P.Column Statement
170−parseIf = If <$> parseIfStatement
171−
172−parseIfStatement :: P.Parsec String P.Column IfStatement
173−parseIfStatement =
174− IfStatement <$> (C.reserved "if" *> C.indented *> parseValue <* C.indented <* C.colon)
175− <*> parseManyStatements
176− <*> P.optionMaybe (C.same *> parseElseStatement)
177−
178−parseElseStatement :: P.Parsec String P.Column ElseStatement
179−parseElseStatement = C.reserved "else" >> (ElseIf <$> (C.indented *> parseIfStatement)
180− <|> Else <$> (C.indented *> C.colon *> parseManyStatements))
181−
182−parseReturn :: P.Parsec String P.Column Statement
183−parseReturn = Return <$> (C.reserved "return" *> parseValue)
184−
185−parseStatement :: P.Parsec String P.Column Statement
186−parseStatement = P.choice (map P.try
187− [ parseVariableIntroduction
188− , parseAssignment
189− , parseWhile
190− , parseFor
191− , parseForEach
192− , parseIf
193− , parseReturn ])
194−
195−parseStringBinder :: P.Parsec String P.Column Binder
196−parseStringBinder = StringBinder <$> C.stringLiteral
197−
198−parseBooleanBinder :: P.Parsec String P.Column Binder
199−parseBooleanBinder = BooleanBinder <$> booleanLiteral
200−
201−parseNumberBinder :: P.Parsec String P.Column Binder
202−parseNumberBinder = NumberBinder <$> C.integerOrFloat
203−
204−parseVarBinder :: P.Parsec String P.Column Binder
205−parseVarBinder = VarBinder <$> C.parseIdent
206−
207−parseNullaryBinder :: P.Parsec String P.Column Binder
208−parseNullaryBinder = NullaryBinder <$> C.lexeme C.properName
209−
210−parseUnaryBinder :: P.Parsec String P.Column Binder
211−parseUnaryBinder = UnaryBinder <$> C.lexeme C.properName <*> (C.indented *> parseBinder)
212−
213−parseObjectBinder :: P.Parsec String P.Column Binder
214−parseObjectBinder = ObjectBinder <$> C.braces ((C.indented *> parseIdentifierAndBinder) `P.sepBy` (C.indented *> C.comma))
215−
216−parseArrayBinder :: P.Parsec String P.Column Binder
217−parseArrayBinder = C.squares $ ArrayBinder <$> ((C.indented *> parseBinder) `P.sepBy` (C.indented *> C.comma))
218− <*> P.optionMaybe (C.indented *> C.colon *> C.indented *> parseBinder)
219−
220−parseNamedBinder :: P.Parsec String P.Column Binder
221−parseNamedBinder = NamedBinder <$> (C.parseIdent <* C.indented <* C.lexeme (P.char '@'))
222− <*> (C.indented *> parseBinder)
223−
224−parseNullBinder :: P.Parsec String P.Column Binder
225−parseNullBinder = C.lexeme (P.char '_') *> P.notFollowedBy C.identLetter *> return NullBinder
226−
227−parseIdentifierAndBinder :: P.Parsec String P.Column (String, Binder)
228−parseIdentifierAndBinder = do
229− name <- C.lexeme C.identifier
230− C.lexeme $ C.indented *> P.char '='
231− binder <- C.indented *> parseBinder
232− return (name, binder)
233−
234−parseBinder :: P.Parsec String P.Column Binder
235−parseBinder = P.choice (map P.try
236− [ parseNullBinder
237− , parseStringBinder
238− , parseBooleanBinder
239− , parseNumberBinder
240− , parseNamedBinder
241− , parseVarBinder
242− , parseUnaryBinder
243− , parseNullaryBinder
244− , parseObjectBinder
245− , parseArrayBinder
246− , C.parens parseBinder ])
247−
248−parseGuardedBinder :: P.Parsec String P.Column Binder
249−parseGuardedBinder = flip ($) <$> parseBinder <*> P.option id (GuardedBinder <$> (C.indented *> C.lexeme (P.char '|') *> C.indented *> parseValue))
250−
251−parseAssignmentTarget :: P.Parsec String P.Column AssignmentTarget
252−parseAssignmentTarget = buildExpressionParser operators (AssignVariable <$> C.parseIdent)
253− where
254− operators = [ [ Postfix $ AssignArrayIndex <$> (C.indented *> C.squares parseValue)
255− , Postfix $ AssignObjectProperty <$> (C.indented *> C.dot *> C.indented *> C.identifier) ] ]
src/PureScript/TypeChecker.hsdeleted−88
@@ -1,88 +0,0 @@
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−import PureScript.TypeChecker.Synonyms
28−
29−import Data.List
30−import Data.Maybe
31−import Data.Function
32−
33−import PureScript.Values
34−import PureScript.Types
35−import PureScript.Kinds
36−import PureScript.Declarations
37−
38−import Control.Monad.State
39−import Control.Monad.Error
40−
41−import qualified Data.Map as M
42−
43−typeCheckAll :: [Declaration] -> Check ()
44−typeCheckAll [] = return ()
45−typeCheckAll (DataDeclaration name args dctors : rest) = do
46− rethrow (("Error in type constructor " ++ name ++ ": ") ++) $ do
47− env <- getEnv
48− guardWith (name ++ " is already defined") $ not $ M.member name (types env)
49− ctorKind <- kindsOf (Just name) args (catMaybes $ map snd dctors)
50− putEnv $ env { types = M.insert name (ctorKind, Data) (types env) }
51− flip mapM_ dctors $ \(dctor, maybeTy) ->
52− rethrow (("Error in data constructor " ++ name ++ ": ") ++) $ do
53− env' <- getEnv
54− guardWith (dctor ++ " is already defined") $ not $ flip M.member (dataConstructors env') dctor
55− let retTy = foldl TypeApp (TypeConstructor name) (map TypeVar args)
56− let dctorTy = maybe retTy (\ty -> Function [ty] retTy) maybeTy
57− let polyType = PolyType args dctorTy
58− putEnv $ env' { dataConstructors = M.insert dctor polyType (dataConstructors env') }
59− typeCheckAll rest
60−typeCheckAll (TypeSynonymDeclaration name args ty : rest) = do
61− rethrow (("Error in type synonym " ++ name ++ ": ") ++) $ do
62− env <- getEnv
63− guardWith (name ++ " is already defined") $ not $ M.member name (types env)
64− kind <- kindsOf (Just name) args [ty]
65− putEnv $ env { types = M.insert name (kind, TypeSynonym) (types env)
66− , typeSynonyms = M.insert name (args, ty) (typeSynonyms env) }
67− typeCheckAll rest
68−typeCheckAll (TypeDeclaration name ty : ValueDeclaration name' val : rest) | name == name' =
69− typeCheckAll (ValueDeclaration name (TypedValue val ty) : rest)
70−typeCheckAll (TypeDeclaration name _ : _) = throwError $ "Orphan type declaration for " ++ show name
71−typeCheckAll (ValueDeclaration name val : rest) = do
72− rethrow (("Error in declaration " ++ show name ++ ": ") ++) $ do
73− env <- getEnv
74− case M.lookup name (names env) of
75− Just ty -> throwError $ show name ++ " is already defined"
76− Nothing -> do
77− ty <- typeOf name val
78− putEnv (env { names = M.insert name (ty, Value) (names env) })
79− typeCheckAll rest
80−typeCheckAll (ExternDeclaration name ty : rest) = do
81− rethrow (("Error in extern declaration " ++ show name ++ ": ") ++) $ do
82− env <- getEnv
83− kind <- kindOf ty
84− guardWith "Expected kind *" $ kind == Star
85− case M.lookup name (names env) of
86− Just _ -> throwError $ show name ++ " is already defined"
87− Nothing -> putEnv (env { names = M.insert name (ty, Extern) (names env) })
88− typeCheckAll rest
src/PureScript/TypeChecker/Kinds.hsdeleted−168
@@ -1,168 +0,0 @@
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− kindOf
20−) where
21−
22−import Data.List
23−import Data.Maybe (fromMaybe)
24−import Data.Function
25−
26−import PureScript.Types
27−import PureScript.Kinds
28−import PureScript.Declarations
29−import PureScript.TypeChecker.Monad
30−
31−import Control.Monad.State
32−import Control.Monad.Error
33−
34−import Control.Applicative
35−import Control.Arrow (Kleisli(..), (***))
36−import qualified Control.Category as C
37−
38−import qualified Data.Map as M
39−
40−data KindConstraint = KindConstraint Int Kind
41−
42−instance Show KindConstraint where
43− show (KindConstraint n k) = show n ++ " = " ++ show k
44−
45−newtype KindSolution = KindSolution { runKindSolution :: Int -> Kind }
46−
47−emptyKindSolution :: KindSolution
48−emptyKindSolution = KindSolution KUnknown
49−
50−kindOf :: PolyType -> Check Kind
51−kindOf (PolyType idents ty) = do
52− ns <- replicateM (length idents) fresh
53− (cs, n, m) <- kindConstraints (M.fromList (zip idents ns)) ty
54− solution <- solveKindConstraints cs emptyKindSolution
55− return $ starIfUnknown $ runKindSolution solution n
56−
57−kindsOf :: Maybe String -> [String] -> [Type] -> Check Kind
58−kindsOf name args ts = do
59− tyCon <- fresh
60− nargs <- replicateM (length args) fresh
61− (cs, ns, m) <- kindConstraintsAll (maybe id (flip M.insert tyCon) name $ M.fromList (zipWith (,) args nargs)) ts
62− let extraConstraints = KindConstraint tyCon (foldr FunKind Star (map KUnknown nargs)) : map (flip KindConstraint Star) ns
63− solution <- solveKindConstraints (extraConstraints ++ cs) emptyKindSolution
64− return $ starIfUnknown $ runKindSolution solution tyCon
65−
66−starIfUnknown :: Kind -> Kind
67−starIfUnknown (KUnknown _) = Star
68−starIfUnknown (FunKind k1 k2) = FunKind (starIfUnknown k1) (starIfUnknown k2)
69−starIfUnknown k = k
70−
71−kindConstraintsAll :: M.Map String Int -> [Type] -> Check ([KindConstraint], [Int], M.Map String Int)
72−kindConstraintsAll m [] = return ([], [], m)
73−kindConstraintsAll m (t:ts) = do
74− (cs, n1, m') <- kindConstraints m t
75− (cs', ns, m'') <- kindConstraintsAll m' ts
76− return ((KindConstraint n1 Star) : cs ++ cs', n1:ns, m'')
77−
78−kindConstraints :: M.Map String Int -> Type -> Check ([KindConstraint], Int, M.Map String Int)
79−kindConstraints m (Array t) = do
80− me <- fresh
81− (cs, n1, m') <- kindConstraints m t
82− return ((KindConstraint n1 Star) : (KindConstraint me Star) : cs, me, m')
83−kindConstraints m (Object row) = do
84− me <- fresh
85− (cs, row, m') <- kindConstraintsForRow m row
86− return ((KindConstraint me Star) : (KindConstraint row Row) : cs, me, m')
87−kindConstraints m (Function args ret) = do
88− me <- fresh
89− (cs, ns, m') <- kindConstraintsAll m args
90− (cs', retN, m'') <- kindConstraints m' ret
91− return ((KindConstraint retN Star) : (KindConstraint me Star) : (map (flip KindConstraint Star) ns) ++ cs, me, m'')
92−kindConstraints m (TypeVar v) = do
93− case M.lookup v m of
94− Just u -> return ([], u, m)
95− Nothing -> throwError $ "Unbound type variable " ++ v
96−kindConstraints m (TypeConstructor v) = do
97− env <- getEnv
98− me <- fresh
99− case M.lookup v m of
100− Nothing -> case M.lookup v (types env) of
101− Nothing -> throwError $ "Unknown type constructor '" ++ v ++ "'"
102− Just (kind, _) -> return ([KindConstraint me kind], me, m)
103− Just u -> do
104− return ([KindConstraint me (KUnknown u)], me, m)
105−kindConstraints m (TypeApp t1 t2) = do
106− me <- fresh
107− (cs1, n1, m1) <- kindConstraints m t1
108− (cs2, n2, m2) <- kindConstraints m1 t2
109− return ((KindConstraint n1 (FunKind (KUnknown n2) (KUnknown me))) : cs1 ++ cs2, me, m2)
110−kindConstraints m _ = do
111− me <- fresh
112− return ([KindConstraint me Star], me, m)
113−
114−kindConstraintsForRow :: M.Map String Int -> Row -> Check ([KindConstraint], Int, M.Map String Int)
115−kindConstraintsForRow m (RowVar v) = do
116− me <- case M.lookup v m of
117− Just u -> return u
118− Nothing -> fresh
119− return ([KindConstraint me Row], me, M.insert v me m)
120−kindConstraintsForRow m REmpty = do
121− me <- fresh
122− return ([KindConstraint me Row], me, m)
123−kindConstraintsForRow m (RCons _ ty row) = do
124− me <- fresh
125− (cs1, n1, m1) <- kindConstraints m ty
126− (cs2, n2, m2) <- kindConstraintsForRow m1 row
127− return ((KindConstraint me Row) : (KindConstraint n1 Star) : (KindConstraint n2 Row) : cs1 ++ cs2, me, m2)
128−
129−solveKindConstraints :: [KindConstraint] -> KindSolution -> Check KindSolution
130−solveKindConstraints [] s = return s
131−solveKindConstraints all@(KindConstraint n k:cs) s = do
132− guardWith "Occurs check failed" $ not $ kindOccursCheck False n k
133− let s' = KindSolution $ replaceUnknownKind n k . runKindSolution s
134− cs' <- fmap concat $ mapM (substituteKindConstraint n k) cs
135− solveKindConstraints cs' s'
136−
137−substituteKindConstraint :: Int -> Kind -> KindConstraint -> Check [KindConstraint]
138−substituteKindConstraint n k (KindConstraint m l)
139− | n == m = unifyKinds k l
140− | otherwise = return [KindConstraint m (replaceUnknownKind n k l)]
141−
142−replaceUnknownKind :: Int -> Kind -> Kind -> Kind
143−replaceUnknownKind n k = f
144− where
145− f (KUnknown m) | m == n = k
146− f (FunKind k1 k2) = FunKind (f k2) (f k2)
147− f other = other
148−
149−unifyKinds :: Kind -> Kind -> Check [KindConstraint]
150−unifyKinds (KUnknown u1) (KUnknown u2) | u1 == u2 = return []
151−unifyKinds (KUnknown u) k = do
152− guardWith "Occurs check failed" $ not $ kindOccursCheck False u k
153− return [KindConstraint u k]
154−unifyKinds k (KUnknown u) = do
155− guardWith "Occurs check failed" $ not $ kindOccursCheck False u k
156− return [KindConstraint u k]
157−unifyKinds Star Star = return []
158−unifyKinds Row Row = return []
159−unifyKinds (FunKind k1 k2) (FunKind k3 k4) = do
160− cs1 <- unifyKinds k1 k3
161− cs2 <- unifyKinds k2 k4
162− return $ cs1 ++ cs2
163−unifyKinds k1 k2 = throwError $ "Cannot unify " ++ show k1 ++ " with " ++ show k2 ++ "."
164−
165−kindOccursCheck :: Bool -> Int -> Kind -> Bool
166−kindOccursCheck b u (KUnknown u') | u == u' = b
167−kindOccursCheck _ u (FunKind k1 k2) = kindOccursCheck True u k1 || kindOccursCheck True u k2
168−kindOccursCheck _ _ _ = False
src/PureScript/TypeChecker/Monad.hsdeleted−67
@@ -1,67 +0,0 @@
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−import PureScript.Names
22−
23−import Control.Applicative
24−import Control.Monad.State
25−import Control.Monad.Error
26−
27−import Control.Arrow ((***))
28−
29−import qualified Data.Map as M
30−
31−data NameKind = Value | Extern deriving Show
32−
33−data TypeDeclarationKind = Data | TypeSynonym deriving Show
34−
35−data Environment = Environment
36− { names :: M.Map Ident (PolyType, NameKind)
37− , types :: M.Map String (Kind, TypeDeclarationKind)
38− , dataConstructors :: M.Map String PolyType
39− , typeSynonyms :: M.Map String ([String], Type)
40− }
41−
42−emptyEnvironment :: Environment
43−emptyEnvironment = Environment M.empty M.empty M.empty M.empty
44−
45−newtype Check a = Check { unCheck :: StateT (Environment, Int) (Either String) a } deriving (Functor, Monad, Applicative, MonadPlus, MonadState (Environment, Int), MonadError String)
46−
47−getEnv :: Check Environment
48−getEnv = fmap fst get
49−
50−putEnv :: Environment -> Check ()
51−putEnv env = fmap (const env *** id) get >>= put
52−
53−fresh :: Check Int
54−fresh = do
55− (env, n) <- get
56− put (env, n + 1)
57− return n
58−
59−check :: Check a -> Either String (a, Environment)
60−check = fmap (id *** fst) . flip runStateT (emptyEnvironment, 0) . unCheck
61−
62−guardWith :: (MonadError e m) => e -> Bool -> m ()
63−guardWith _ True = return ()
64−guardWith e False = throwError e
65−
66−rethrow :: (MonadError e m) => (e -> e) -> m a -> m a
67−rethrow f = flip catchError $ \e -> throwError (f e)
src/PureScript/TypeChecker/Synonyms.hsdeleted−58
@@ -1,58 +0,0 @@
1−-----------------------------------------------------------------------------
2−--
3−-- Module : PureScript.TypeChecker.Synonyms
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 Rank2Types #-}
16−
17−module PureScript.TypeChecker.Synonyms (
18− substituteTypeSynonym
19−) where
20−
21−import PureScript.Types
22−import PureScript.Declarations
23−
24−import Data.Maybe (fromMaybe)
25−import Data.Data
26−import Data.Generics
27−import Control.Arrow
28−import Control.Monad.Writer
29−import Control.Monad.Error
30−import qualified Data.Map as M
31−
32−replaceTypeVars :: M.Map String Type -> Type -> Type
33−replaceTypeVars m = everywhere (mkT replace)
34− where
35− replace :: Type -> Type
36− replace t@(TypeVar var) = fromMaybe t (M.lookup var m)
37− replace t = t
38−
39−buildTypeSubstitution :: String -> Type -> [String] -> Type -> WriterT Any (Either String) (Maybe Type)
40−buildTypeSubstitution name ty args = go (reverse args) M.empty
41− where
42− go :: [String] -> M.Map String Type -> Type -> WriterT Any (Either String) (Maybe Type)
43− go [] m (TypeConstructor ctor) | name == ctor = tell (Any True) >> return (Just $ replaceTypeVars m ty)
44− go (_:_) _ (TypeConstructor ctor) | name == ctor = lift . throwError $ "Partially applied type synonym " ++ name
45− go (arg:args) m (TypeApp f x) = go args (M.insert arg x m) f
46− go _ _ _ = return Nothing
47−
48−everywhereButM' :: (Monad m, Data d) => (forall d. (Data d) => d -> WriterT Any m d) -> d -> m d
49−everywhereButM' f x = do
50− (y, halt) <- runWriterT $ f x
51− case getAny halt of
52− True -> return y
53− _ -> gmapM (everywhereButM' f) y
54−
55−substituteTypeSynonym :: String -> [String] -> Type -> Type -> Either String Type
56−substituteTypeSynonym name args ty = everywhereButM' (mkM replace)
57− where
58− replace t = fmap (fromMaybe t) $ buildTypeSubstitution name ty args t
src/PureScript/TypeChecker/Types.hsdeleted−571
@@ -1,571 +0,0 @@
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−import Data.Data (Data(..))
24−import Data.Generics (everywhere, everywhereM, everything, mkT, mkM, mkQ, extM, extQ)
25−
26−import PureScript.Values
27−import PureScript.Types
28−import PureScript.Kinds
29−import PureScript.Names
30−import PureScript.TypeChecker.Monad
31−import PureScript.TypeChecker.Kinds
32−import PureScript.TypeChecker.Synonyms
33−
34−import Control.Monad.State
35−import Control.Monad.Error
36−
37−import Control.Applicative
38−import Control.Arrow (Kleisli(..), (***), (&&&))
39−import qualified Control.Category as C
40−
41−import qualified Data.Map as M
42−
43−data TypeConstraint
44− = TypeConstraint Int Type
45− | RowConstraint Int Row deriving Show
46−
47−newtype TypeSolution = TypeSolution { runTypeSolution :: (Int -> Type, Int -> Row) }
48−
49−emptyTypeSolution :: TypeSolution
50−emptyTypeSolution = TypeSolution (TUnknown, RUnknown)
51−
52−typeOf :: Ident -> Value -> Check PolyType
53−typeOf name val = do
54− (cs, n) <- case val of
55− Abs _ _ -> do
56− me <- fresh
57− (cs, n) <- typeConstraints (M.singleton name me) val
58− return (TypeConstraint me (TUnknown n) : cs, n)
59− _ -> typeConstraints M.empty val
60− solution <- solveTypeConstraints cs emptyTypeSolution
61− let ty = fst (runTypeSolution solution) n
62− allUnknownsBecameQuantified cs solution ty
63− return $ varIfUnknown ty
64−
65−allUnknownsBecameQuantified :: [TypeConstraint] -> TypeSolution -> Type -> Check ()
66−allUnknownsBecameQuantified cs solution ty = do
67− let
68− typesMentioned = findUnknownTypes ty
69− unknownTypes = nub $ flip concatMap cs $ \c -> case c of
70− TypeConstraint u t -> u : findUnknownTypes t
71− RowConstraint _ r -> findUnknownTypes r
72− unsolvedTypes = filter (\n -> TUnknown n == fst (runTypeSolution solution) n) unknownTypes
73− guardWith "Unsolved type variable" $ null $ unsolvedTypes \\ typesMentioned
74− let
75− rowsMentioned = findUnknownRows ty
76− unknownRows = nub $ flip concatMap cs $ \c -> case c of
77− TypeConstraint _ t -> findUnknownRows t
78− RowConstraint u r -> u : findUnknownRows r
79− unsolvedRows = filter (\n -> RUnknown n == snd (runTypeSolution solution) n) unknownRows
80− guardWith ("Unsolved row variable" ++ show (unsolvedRows \\ rowsMentioned) ++ ", " ++ show cs) $ null $ unsolvedRows \\ rowsMentioned
81−
82−findUnknownTypes :: (Data d) => d -> [Int]
83−findUnknownTypes = everything (++) (mkQ [] f)
84− where
85− f :: Type -> [Int]
86− f (TUnknown n) = [n]
87− f _ = []
88−
89−findTypeVars :: (Data d) => d -> [String]
90−findTypeVars = everything (++) (mkQ [] f)
91− where
92− f :: Type -> [String]
93− f (TypeVar v) = [v]
94− f _ = []
95−
96−findUnknownRows :: (Data d) => d -> [Int]
97−findUnknownRows = everything (++) (mkQ [] f)
98− where
99− f :: Row -> [Int]
100− f (RUnknown n) = [n]
101− f _ = []
102−
103−varIfUnknown :: Type -> PolyType
104−varIfUnknown ty =
105− let
106− (ty', m) = flip runState M.empty $ everywhereM (flip extM g $ mkM f) ty
107− in
108− PolyType (sort $ nub $ M.elems m ++ findTypeVars ty) ty'
109− where
110− f :: Type -> State (M.Map Int String) Type
111− f (TUnknown n) = do
112− m <- get
113− case M.lookup n m of
114− Nothing -> do
115− let name = "t" ++ show (M.size m)
116− put $ M.insert n name m
117− return $ TypeVar name
118− Just name -> return $ TypeVar name
119− f t = return t
120− g :: Row -> State (M.Map Int String) Row
121− g (RUnknown n) = do
122− m <- get
123− case M.lookup n m of
124− Nothing -> do
125− let name = "r" ++ show (M.size m)
126− put $ M.insert n name m
127− return $ RowVar name
128− Just name -> return $ RowVar name
129− g r = return r
130−
131−replaceVarsWithUnknowns :: [String] -> Type -> Check Type
132−replaceVarsWithUnknowns idents = flip evalStateT M.empty . everywhereM (flip extM f $ mkM g)
133− where
134− f :: Type -> StateT (M.Map String Int) Check Type
135− f (TypeVar var) | var `elem` idents = do
136− m <- get
137− n <- lift fresh
138− case M.lookup var m of
139− Nothing -> do
140− put (M.insert var n m)
141− return $ TUnknown n
142− Just u -> return $ TUnknown u
143− f t = return t
144− g :: Row -> StateT (M.Map String Int) Check Row
145− g (RowVar var) | var `elem` idents = do
146− m <- get
147− n <- lift fresh
148− case M.lookup var m of
149− Nothing -> do
150− put (M.insert var n m)
151− return $ RUnknown n
152− Just u -> return $ RUnknown u
153− g r = return r
154−
155−replaceType :: (Data d) => Int -> Type -> d -> d
156−replaceType n t = everywhere (mkT go)
157− where
158− go (TUnknown m) | m == n = t
159− go t = t
160−
161−replaceRow :: (Data d) => Int -> Row -> d -> d
162−replaceRow n r = everywhere (mkT go)
163− where
164− go (RUnknown m) | m == n = r
165− go r = r
166−
167−typeOccursCheck :: Int -> Type -> Check ()
168−typeOccursCheck u (TUnknown _) = return ()
169−typeOccursCheck u t = when (occursCheck u t) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ show t
170−
171−rowOccursCheck :: Int -> Row -> Check ()
172−rowOccursCheck u (RUnknown _) = return ()
173−rowOccursCheck u r = when (occursCheck u r) $ throwError $ "Occurs check failed: " ++ show u ++ " = " ++ show r
174−
175−occursCheck :: (Data d) => Int -> d -> Bool
176−occursCheck u = everything (||) $ flip extQ g $ mkQ False f
177− where
178− f (TUnknown u') | u' == u = True
179− f _ = False
180− g (RUnknown u') | u' == u = True
181− g _ = False
182−
183−typeConstraints :: M.Map Ident Int -> Value -> Check ([TypeConstraint], Int)
184−typeConstraints _ (NumericLiteral _) = do
185− me <- fresh
186− return ([TypeConstraint me Number], me)
187−typeConstraints _ (StringLiteral _) = do
188− me <- fresh
189− return ([TypeConstraint me String], me)
190−typeConstraints _ (BooleanLiteral _) = do
191− me <- fresh
192− return ([TypeConstraint me Boolean], me)
193−typeConstraints m (ArrayLiteral vals) = do
194− all <- mapM (typeConstraints m) vals
195− let (cs, ns) = (concat . map fst &&& map snd) all
196− me <- fresh
197− return (cs ++ map (TypeConstraint me . Array . TUnknown) ns, me)
198−typeConstraints m (Unary op val) = do
199− (cs, n1) <- typeConstraints m val
200− me <- fresh
201− return (cs ++ unaryOperatorConstraints op n1 me, me)
202−typeConstraints m (Binary op left right) = do
203− (cs1, n1) <- typeConstraints m left
204− (cs2, n2) <- typeConstraints m right
205− me <- fresh
206− return (cs1 ++ cs2 ++ binaryOperatorConstraints op n1 n2 me, me)
207−typeConstraints m (ObjectLiteral ps) = do
208− all <- mapM (typeConstraints m . snd) ps
209− let (cs, ns) = (concat . map fst &&& map snd) all
210− me <- fresh
211− let tys = zipWith (\(name, _) u -> (name, TUnknown u)) ps ns
212− return ((TypeConstraint me (Object (typesToRow tys))) : cs, me)
213− where
214− typesToRow [] = REmpty
215− typesToRow ((name, ty):tys) = RCons name ty (typesToRow tys)
216−typeConstraints m (Indexer index val) = do
217− (cs1, n1) <- typeConstraints m index
218− (cs2, n2) <- typeConstraints m val
219− me <- fresh
220− return ((TypeConstraint n1 Number) : (TypeConstraint n2 (Array (TUnknown me))) : cs1 ++ cs2, me)
221−typeConstraints m (Accessor prop val) = do
222− (cs, n1) <- typeConstraints m val
223− me <- fresh
224− rest <- fresh
225− return ((TypeConstraint n1 (Object (RCons prop (TUnknown me) (RUnknown rest)))) : cs, me)
226−typeConstraints m (Abs args ret) = do
227− ns <- replicateM (length args) fresh
228− let m' = m `M.union` M.fromList (zipWith (,) args ns)
229− (cs, n') <- typeConstraints m' ret
230− me <- fresh
231− return ((TypeConstraint me (Function (map TUnknown ns) (TUnknown n'))) : cs, me)
232−typeConstraints m (App f xs) = do
233− (cs1, n1) <- typeConstraints m f
234− all <- mapM (typeConstraints m) xs
235− let (cs2, ns) = (concat . map fst &&& map snd) all
236− me <- fresh
237− return ((TypeConstraint n1 (Function (map TUnknown ns) (TUnknown me))) : cs1 ++ cs2, me)
238−typeConstraints m (Var var) =
239− case M.lookup var m of
240− Nothing -> do
241− env <- getEnv
242− case M.lookup var (names env) of
243− Nothing -> throwError $ show var ++ " is undefined"
244− Just (PolyType idents ty, _) -> do
245− me <- fresh
246− replaced <- replaceVarsWithUnknowns idents ty
247− return ([TypeConstraint me replaced], me)
248− Just u -> do
249− me <- fresh
250− return ([TypeConstraint u (TUnknown me)], me)
251−typeConstraints m (Block ss) = do
252− ret <- fresh
253− (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m M.empty ret ss
254− guardWith "Block is missing a return statement" allCodePathsReturn
255− return (cs, ret)
256−typeConstraints m (Constructor c) = do
257− env <- getEnv
258− case M.lookup c (dataConstructors env) of
259− Nothing -> throwError $ "Constructor " ++ c ++ " is undefined"
260− Just (PolyType idents ty) -> do
261− me <- fresh
262− replaced <- replaceVarsWithUnknowns idents ty
263− return ([TypeConstraint me replaced], me)
264−typeConstraints m (Case val binders) = do
265− (cs1, n1) <- typeConstraints m val
266− ret <- fresh
267− cs2 <- typeConstraintsForBinders m n1 ret binders
268− return (cs1 ++ cs2, ret)
269−typeConstraints m (IfThenElse cond th el) = do
270− (cs1, n1) <- typeConstraints m cond
271− (cs2, n2) <- typeConstraints m th
272− (cs3, n3) <- typeConstraints m el
273− return (TypeConstraint n1 Boolean : TypeConstraint n2 (TUnknown n3) : cs1 ++ cs2 ++ cs3, n2)
274−typeConstraints m (TypedValue val poly@(PolyType idents ty)) = do
275− kind <- kindOf poly
276− guardWith ("Expected type of kind *, was " ++ show kind) $ kind == Star
277− desugared <- replaceAllTypeSynonyms ty
278− (cs, n1) <- typeConstraints m val
279− return (TypeConstraint n1 desugared : cs, n1)
280−
281−replaceAllTypeSynonyms :: Type -> Check Type
282−replaceAllTypeSynonyms ty = do
283− env <- getEnv
284− go (M.toList $ typeSynonyms env) ty
285− where
286− go [] ty = return ty
287− go ((name, (args, repl)):rest) ty = do
288− ty' <- either throwError return (substituteTypeSynonym name args repl ty)
289− go rest ty'
290−
291−unaryOperatorConstraints :: UnaryOperator -> Int -> Int -> [TypeConstraint]
292−unaryOperatorConstraints Negate val result = [TypeConstraint val Number, TypeConstraint result Number]
293−unaryOperatorConstraints Not val result = [TypeConstraint val Boolean, TypeConstraint result Boolean]
294−unaryOperatorConstraints BitwiseNot val result = [TypeConstraint val Number, TypeConstraint result Number]
295−
296−binaryOperatorConstraints :: BinaryOperator -> Int -> Int -> Int -> [TypeConstraint]
297−binaryOperatorConstraints Add = symBinOpConstraints Number
298−binaryOperatorConstraints Subtract = symBinOpConstraints Number
299−binaryOperatorConstraints Multiply = symBinOpConstraints Number
300−binaryOperatorConstraints Divide = symBinOpConstraints Number
301−binaryOperatorConstraints Modulus = symBinOpConstraints Number
302−binaryOperatorConstraints LessThan = asymBinOpConstraints Number Boolean
303−binaryOperatorConstraints LessThanOrEqualTo = asymBinOpConstraints Number Boolean
304−binaryOperatorConstraints GreaterThan = asymBinOpConstraints Number Boolean
305−binaryOperatorConstraints GreaterThanOrEqualTo = asymBinOpConstraints Number Boolean
306−binaryOperatorConstraints BitwiseAnd = symBinOpConstraints Number
307−binaryOperatorConstraints BitwiseOr = symBinOpConstraints Number
308−binaryOperatorConstraints BitwiseXor = symBinOpConstraints Number
309−binaryOperatorConstraints ShiftLeft = symBinOpConstraints Number
310−binaryOperatorConstraints ShiftRight = symBinOpConstraints Number
311−binaryOperatorConstraints ZeroFillShiftRight = symBinOpConstraints Number
312−binaryOperatorConstraints EqualTo = equalityBinOpConstraints
313−binaryOperatorConstraints NotEqualTo = equalityBinOpConstraints
314−binaryOperatorConstraints And = symBinOpConstraints Boolean
315−binaryOperatorConstraints Or = symBinOpConstraints Boolean
316−binaryOperatorConstraints Concat = symBinOpConstraints String
317−
318−equalityBinOpConstraints :: Int -> Int -> Int -> [TypeConstraint]
319−equalityBinOpConstraints left right result = [TypeConstraint left (TUnknown right), TypeConstraint result Boolean]
320−
321−symBinOpConstraints :: Type -> Int -> Int -> Int -> [TypeConstraint]
322−symBinOpConstraints ty left right result = asymBinOpConstraints ty ty left right result
323−
324−asymBinOpConstraints :: Type -> Type -> Int -> Int -> Int -> [TypeConstraint]
325−asymBinOpConstraints ty res left right result = [TypeConstraint left ty, TypeConstraint right ty, TypeConstraint result res]
326−
327−typeConstraintsForBinder :: Int -> Binder -> Check ([TypeConstraint], M.Map Ident Int)
328−typeConstraintsForBinder _ NullBinder = return ([], M.empty)
329−typeConstraintsForBinder val (StringBinder _) = constantBinder val String
330−typeConstraintsForBinder val (NumberBinder _) = constantBinder val Number
331−typeConstraintsForBinder val (BooleanBinder _) = constantBinder val Boolean
332−typeConstraintsForBinder val (VarBinder name) = do
333− me <- fresh
334− return ([TypeConstraint me (TUnknown val)], M.singleton name me)
335−typeConstraintsForBinder val (NullaryBinder ctor) = do
336− env <- getEnv
337− case M.lookup ctor (dataConstructors env) of
338− Just (PolyType args ret) -> do
339− ret' <- replaceVarsWithUnknowns args ret
340− return ([TypeConstraint val ret'], M.empty)
341− _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
342−typeConstraintsForBinder val (UnaryBinder ctor binder) = do
343− env <- getEnv
344− case M.lookup ctor (dataConstructors env) of
345− Just (PolyType idents f@(Function [_] _)) -> do
346− obj <- fresh
347− (Function [ty] ret) <- replaceVarsWithUnknowns idents f
348− (cs, m1) <- typeConstraintsForBinder obj binder
349− return ((TypeConstraint val ret) : (TypeConstraint obj ty) : cs, m1)
350− Just _ -> throwError $ ctor ++ " is not a unary constructor"
351− _ -> throwError $ "Constructor " ++ ctor ++ " is not defined"
352−typeConstraintsForBinder val (ObjectBinder props) = do
353− row <- fresh
354− rest <- fresh
355− (cs, m1) <- typeConstraintsForProperties row (RUnknown rest) props
356− return ((TypeConstraint val (Object (RUnknown row))) : cs, m1)
357− where
358− typeConstraintsForProperties :: Int -> Row -> [(String, Binder)] -> Check ([TypeConstraint], M.Map Ident Int)
359− typeConstraintsForProperties nrow row [] = return ([RowConstraint nrow row], M.empty)
360− typeConstraintsForProperties nrow row ((name, binder):binders) = do
361− propTy <- fresh
362− (cs1, m1) <- typeConstraintsForBinder propTy binder
363− (cs2, m2) <- typeConstraintsForProperties nrow (RCons name (TUnknown propTy) row) binders
364− return (cs1 ++ cs2, M.union m1 m2)
365−typeConstraintsForBinder val (ArrayBinder binders rest) = do
366− el <- fresh
367− all <- mapM (typeConstraintsForBinder el) binders
368− let (cs1, m1) = (concat . map fst &&& M.unions . map snd) all
369− let arrayConstraint = TypeConstraint val (Array (TUnknown el))
370− case rest of
371− Nothing -> return (arrayConstraint : cs1, m1)
372− Just binder -> do
373− (cs2, m2) <- typeConstraintsForBinder val binder
374− return (arrayConstraint : cs1 ++ cs2, M.union m1 m2)
375−typeConstraintsForBinder val (NamedBinder name binder) = do
376− me <- fresh
377− (cs, m) <- typeConstraintsForBinder val binder
378− return (TypeConstraint me (TUnknown val) : cs, M.insert name me m)
379−typeConstraintsForBinder val (GuardedBinder cond binder) = do
380− (cs1, m) <- typeConstraintsForBinder val binder
381− (cs2, n) <- typeConstraints m cond
382− return (TypeConstraint n Boolean : cs1 ++ cs2, m)
383−
384−constantBinder :: Int -> Type -> Check ([TypeConstraint], M.Map Ident Int)
385−constantBinder val ty = return ([TypeConstraint val ty], M.empty)
386−
387−typeConstraintsForBinders :: M.Map Ident Int -> Int -> Int -> [(Binder, Value)] -> Check [TypeConstraint]
388−typeConstraintsForBinders _ _ _ [] = return []
389−typeConstraintsForBinders m nval ret ((binder, val):bs) = do
390− (cs1, m1) <- typeConstraintsForBinder nval binder
391− (cs2, n2) <- typeConstraints (M.union m m1) val
392− cs3 <- typeConstraintsForBinders m nval ret bs
393− return ((TypeConstraint n2 (TUnknown ret)) : cs1 ++ cs2 ++ cs3)
394−
395−assignVariable :: Ident -> M.Map Ident Int -> Check ()
396−assignVariable name m =
397− case M.lookup name m of
398− Nothing -> return ()
399− Just _ -> throwError $ "Variable with name " ++ show name ++ " already exists."
400−
401−typeConstraintsForStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> Statement -> Check ([TypeConstraint], Bool, M.Map Ident Int)
402−typeConstraintsForStatement m mass ret (VariableIntroduction name val) = do
403− assignVariable name (m `M.union` mass)
404− (cs1, n1) <- typeConstraints m val
405− return $ (cs1, False, M.insert name n1 mass)
406−typeConstraintsForStatement m mass ret (Assignment tgt val) = do
407− (cs1, n1) <- typeConstraints m val
408− cs2 <- typeConstraintsForAssignmentTarget m mass n1 tgt
409− return (cs1 ++ cs2, False, mass)
410−typeConstraintsForStatement m mass ret (While val inner) = do
411− (cs1, n1) <- typeConstraints m val
412− (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret inner
413− return $ ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn, mass)
414−typeConstraintsForStatement m mass ret (If ifst) = do
415− (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
416− return $ (cs, allCodePathsReturn, mass)
417−typeConstraintsForStatement m mass ret (For ident start end inner) = do
418− assignVariable ident (m `M.union` mass)
419− (cs1, n1) <- typeConstraints (m `M.union` mass) start
420− (cs2, n2) <- typeConstraints (m `M.union` mass) end
421− let mass1 = M.insert ident n1 mass
422− (cs3, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
423− return $ ((TypeConstraint n1 Number) : (TypeConstraint n2 Number) : cs1 ++ cs2 ++ cs3, allCodePathsReturn, mass)
424−typeConstraintsForStatement m mass ret (ForEach ident vals inner) = do
425− assignVariable ident (m `M.union` mass)
426− val <- fresh
427− (cs1, n1) <- typeConstraints (m `M.union` mass) vals
428− let mass1 = M.insert ident val mass
429− (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock (m `M.union` mass1) mass1 ret inner
430− guardWith "Cannot return from within a foreach block" $ not allCodePathsReturn
431− return $ ((TypeConstraint n1 (Array (TUnknown val))) : cs1 ++ cs2, False, mass)
432−typeConstraintsForStatement m mass ret (Return val) = do
433− (cs1, n1) <- typeConstraints (m `M.union` mass) val
434− return ((TypeConstraint n1 (TUnknown ret)) : cs1, True, mass)
435−
436−typeConstraintsForIfStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> IfStatement -> Check ([TypeConstraint], Bool)
437−typeConstraintsForIfStatement m mass ret (IfStatement val thens Nothing) = do
438− (cs1, n1) <- typeConstraints m val
439− (cs2, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret thens
440− return ((TypeConstraint n1 Boolean) : cs1 ++ cs2, allCodePathsReturn)
441−typeConstraintsForIfStatement m mass ret (IfStatement val thens (Just elses)) = do
442− (cs1, n1) <- typeConstraints m val
443− (cs2, allCodePathsReturn1, _) <- typeConstraintsForBlock m mass ret thens
444− (cs3, allCodePathsReturn2) <- typeConstraintsForElseStatement m mass ret elses
445− return ((TypeConstraint n1 Boolean) : cs1 ++ cs2 ++ cs3, allCodePathsReturn1 && allCodePathsReturn2)
446−
447−typeConstraintsForElseStatement :: M.Map Ident Int -> M.Map Ident Int -> Int -> ElseStatement -> Check ([TypeConstraint], Bool)
448−typeConstraintsForElseStatement m mass ret (Else elses) = do
449− (cs, allCodePathsReturn, _) <- typeConstraintsForBlock m mass ret elses
450− return (cs, allCodePathsReturn)
451−typeConstraintsForElseStatement m mass ret (ElseIf ifst) = do
452− (cs, allCodePathsReturn) <- typeConstraintsForIfStatement m mass ret ifst
453− return (cs, allCodePathsReturn)
454−
455−typeConstraintsForAssignmentTarget :: M.Map Ident Int -> M.Map Ident Int -> Int -> AssignmentTarget -> Check [TypeConstraint]
456−typeConstraintsForAssignmentTarget m mass nval (AssignVariable var) =
457− case M.lookup var mass of
458− Nothing -> throwError $ "No local variable with name " ++ show var
459− Just ty -> do
460− return [TypeConstraint nval (TUnknown ty)]
461−typeConstraintsForAssignmentTarget m mass nval (AssignArrayIndex index tgt) = do
462− arr <- fresh
463− (cs1, n1) <- typeConstraints (m `M.union` mass) index
464− cs2 <- typeConstraintsForAssignmentTarget m mass arr tgt
465− return $ (TypeConstraint arr (Array (TUnknown nval))) : (TypeConstraint n1 Number) : cs1 ++ cs2
466−typeConstraintsForAssignmentTarget m mass nval (AssignObjectProperty prop tgt) = do
467− obj <- fresh
468− row <- fresh
469− cs <- typeConstraintsForAssignmentTarget m mass obj tgt
470− return $ (TypeConstraint obj (Object (RCons prop (TUnknown nval) $ RUnknown row))) : cs
471−
472−typeConstraintsForBlock :: M.Map Ident Int -> M.Map Ident Int -> Int -> [Statement] -> Check ([TypeConstraint], Bool, M.Map Ident Int)
473−typeConstraintsForBlock _ mass _ [] = return ([], False, mass)
474−typeConstraintsForBlock m mass ret (s:ss) = do
475− (cs1, b1, mass1) <- typeConstraintsForStatement (m `M.union` mass) mass ret s
476− case (b1, ss) of
477− (True, []) -> return (cs1, True, mass1)
478− (True, _) -> throwError "Unreachable code"
479− (False, ss) -> do
480− (cs2, b2, mass2) <- typeConstraintsForBlock m mass1 ret ss
481− return (cs1 ++ cs2, b2, mass2)
482−
483−solveTypeConstraints :: [TypeConstraint] -> TypeSolution -> Check TypeSolution
484−solveTypeConstraints [] s = return s
485−solveTypeConstraints all@(TypeConstraint n t:cs) s = do
486− typeOccursCheck n t
487− let s' = let (f, g) = runTypeSolution s
488− in TypeSolution (replaceType n t . f, replaceType n t . g)
489− cs' <- fmap concat $ mapM (substituteTypeInConstraint n t) cs
490− solveTypeConstraints cs' s'
491−solveTypeConstraints (RowConstraint n r:cs) s = do
492− rowOccursCheck n r
493− let s' = let (f, g) = runTypeSolution s
494− in TypeSolution $ (replaceRow n r . f, replaceRow n r . g)
495− cs' <- fmap concat $ mapM (substituteRowInConstraint n r) cs
496− solveTypeConstraints cs' s'
497−
498−substituteTypeInConstraint :: Int -> Type -> TypeConstraint -> Check [TypeConstraint]
499−substituteTypeInConstraint n s (TypeConstraint m t)
500− | n == m = unifyTypes s t
501− | otherwise = return [TypeConstraint m (replaceType n s t)]
502−substituteTypeInConstraint n s (RowConstraint m r)
503− = return [RowConstraint m (replaceType n s r)]
504−
505−substituteRowInConstraint :: Int -> Row -> TypeConstraint -> Check [TypeConstraint]
506−substituteRowInConstraint n r (TypeConstraint m t)
507− = return [TypeConstraint m (replaceRow n r t)]
508−substituteRowInConstraint n r (RowConstraint m r1)
509− | m == n = unifyRows r r1
510− | otherwise = return [RowConstraint m (replaceRow n r r1)]
511−
512−unifyTypes :: Type -> Type -> Check [TypeConstraint]
513−unifyTypes (TUnknown u1) (TUnknown u2) | u1 == u2 = return []
514−unifyTypes (TUnknown u) t = do
515− typeOccursCheck u t
516− return [TypeConstraint u t]
517−unifyTypes t (TUnknown u) = do
518− typeOccursCheck u t
519− return [TypeConstraint u t]
520−unifyTypes Number Number = return []
521−unifyTypes String String = return []
522−unifyTypes Boolean Boolean = return []
523−unifyTypes (Array s) (Array t) = unifyTypes s t
524−unifyTypes (Object row1) (Object row2) = unifyRows row1 row2
525−unifyTypes (Function args1 ret1) (Function args2 ret2) = do
526− guardWith "Function applied to incorrect number of args" $ length args1 == length args2
527− cs1 <- fmap concat $ zipWithM unifyTypes args1 args2
528− cs2 <- unifyTypes ret1 ret2
529− return $ cs1 ++ cs2
530−unifyTypes (TypeVar v1) (TypeVar v2) | v1 == v2 = return []
531−unifyTypes (TypeConstructor c1) (TypeConstructor c2) | c1 == c2 = return []
532−unifyTypes (TypeVar v1) (TypeVar v2) = return []
533−unifyTypes (TypeApp t1 t2) (TypeApp t3 t4) = do
534− cs1 <- unifyTypes t1 t3
535− cs2 <- unifyTypes t2 t4
536− return $ cs1 ++ cs2
537−unifyTypes t1 t2 = throwError $ "Cannot unify " ++ show t1 ++ " with " ++ show t2 ++ "."
538−
539−unifyRows :: Row -> Row -> Check [TypeConstraint]
540−unifyRows r1 r2 =
541− let
542− (s1, r1') = toList r1
543− (s2, r2') = toList r2
544− int = [ (t1, t2) | (name, t1) <- s1, (name', t2) <- s2, name == name' ]
545− sd1 = [ (name, t1) | (name, t1) <- s1, not (elem name (map fst s2)) ]
546− sd2 = [ (name, t2) | (name, t2) <- s2, not (elem name (map fst s1)) ]
547− in rethrow (\e -> "Cannot unify " ++ show r1 ++ " with " ++ show r2 ++ ": " ++ e) $ do
548− cs1 <- fmap concat $ mapM (uncurry unifyTypes) int
549− cs2 <- unifyRows' sd1 r1' sd2 r2'
550− return $ cs1 ++ cs2
551− where
552− unifyRows' :: [(String, Type)] -> Row -> [(String, Type)] -> Row -> Check [TypeConstraint]
553− unifyRows' [] (RUnknown u) sd r = do
554− rowOccursCheck u r
555− return [RowConstraint u (fromList (sd, r))]
556− unifyRows' sd r [] (RUnknown u) = do
557− rowOccursCheck u r
558− return [RowConstraint u (fromList (sd, r))]
559− unifyRows' ((name, ty):row) r others (RUnknown u) = do
560− u' <- fresh
561− cs <- unifyRows' row r others (RUnknown u')
562− return (RowConstraint u (RCons name ty (RUnknown u')) : cs)
563− unifyRows' [] REmpty [] REmpty = return []
564− unifyRows' sd1 r1 sd2 r2 = throwError $ "Cannot unify " ++ show (fromList (sd1, r1)) ++ " with " ++ show (fromList (sd2, r2)) ++ "."
565− toList :: Row -> ([(String, Type)], Row)
566− toList (RCons name ty row) = let (tys, rest) = toList row
567− in ((name, ty):tys, rest)
568− toList r = ([], r)
569− fromList :: ([(String, Type)], Row) -> Row
570− fromList ([], r) = r
571− fromList ((name, t):ts, r) = RCons name t (fromList (ts, r))
src/PureScript/Types.hsdeleted−42
@@ -1,42 +0,0 @@
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 DeriveDataTypeable #-}
16−
17−module PureScript.Types where
18−
19−import Data.Data
20−
21−data Type
22− = TUnknown Int
23− | Number
24− | String
25− | Boolean
26− | Array Type
27− | Object Row
28− | Function [Type] Type
29− | TypeVar String
30− | TypeConstructor String
31− | TypeApp Type Type deriving (Show, Eq, Data, Typeable)
32−
33−data PolyType = PolyType [String] Type deriving (Show, Data, Typeable)
34−
35−data Row
36− = RUnknown Int
37− | RowVar String
38− | REmpty
39− | RCons String Type Row deriving (Show, Eq, Data, Typeable)
40−
41−monoType :: Type -> PolyType
42−monoType = PolyType []
src/PureScript/Values.hsdeleted−101
@@ -1,101 +0,0 @@
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−{-# LANGUAGE DeriveDataTypeable #-}
16−
17−module PureScript.Values where
18−
19−import PureScript.Types
20−import PureScript.Names
21−
22−import Data.Data
23−
24−data UnaryOperator
25− = Negate
26− | Not
27− | BitwiseNot deriving (Show, Eq, Data, Typeable)
28−
29−data BinaryOperator
30− = Add
31− | Subtract
32− | Multiply
33− | Divide
34− | Modulus
35− | EqualTo
36− | NotEqualTo
37− | LessThan
38− | LessThanOrEqualTo
39− | GreaterThan
40− | GreaterThanOrEqualTo
41− | And
42− | Or
43− | BitwiseAnd
44− | BitwiseOr
45− | BitwiseXor
46− | ShiftLeft
47− | ShiftRight
48− | ZeroFillShiftRight
49− | Concat deriving (Show, Eq, Data, Typeable)
50−
51−data Value
52− = NumericLiteral (Either Integer Double)
53− | StringLiteral String
54− | BooleanLiteral Bool
55− | Unary UnaryOperator Value
56− | Binary BinaryOperator Value Value
57− | ArrayLiteral [Value]
58− | Indexer Value Value
59− | ObjectLiteral [(String, Value)]
60− | Accessor String Value
61− | Abs [Ident] Value
62− | App Value [Value]
63− | Var Ident
64− | IfThenElse Value Value Value
65− | Block [Statement]
66− | Constructor String
67− | Case Value [(Binder, Value)]
68− | TypedValue Value PolyType deriving (Show, Data, Typeable)
69−
70−data Statement
71− = VariableIntroduction Ident Value
72− | Assignment AssignmentTarget Value
73− | While Value [Statement]
74− | For Ident Value Value [Statement]
75− | ForEach Ident Value [Statement]
76− | If IfStatement
77− | Return Value deriving (Show, Data, Typeable)
78−
79−data IfStatement = IfStatement Value [Statement] (Maybe ElseStatement) deriving (Show, Data, Typeable)
80−
81−data ElseStatement
82− = Else [Statement]
83− | ElseIf IfStatement deriving (Show, Data, Typeable)
84−
85−data Binder
86− = NullBinder
87− | BooleanBinder Bool
88− | StringBinder String
89− | NumberBinder (Either Integer Double)
90− | VarBinder Ident
91− | NullaryBinder String
92− | UnaryBinder String Binder
93− | ObjectBinder [(String, Binder)]
94− | ArrayBinder [Binder] (Maybe Binder)
95− | NamedBinder Ident Binder
96− | GuardedBinder Value Binder deriving (Show, Data, Typeable)
97−
98−data AssignmentTarget
99− = AssignVariable Ident
100− | AssignObjectProperty String AssignmentTarget
101− | AssignArrayIndex Value AssignmentTarget deriving (Show, Data, Typeable)
src/Tests.hsnew file+141
@@ -0,0 +1,141 @@
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.nixnew file+23
@@ -0,0 +1,23 @@
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.yamlnew file+24
@@ -0,0 +1,24 @@
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.gonew file+30
@@ -0,0 +1,30 @@
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-loadernew file+2
@@ -0,0 +1,2 @@
1+module $PROJECT/purescript-native/ffi-loader
2+
support/go.mod.outputnew file+2
@@ -0,0 +1,2 @@
1+module $PROJECT/purescript-native/output
2+
support/go.mod.workingnew file+1
@@ -0,0 +1 @@
1+module $PROJECT/example
test/Spec.hsnew file+2
@@ -0,0 +1,2 @@
1+main :: IO ()
2+main = putStrLn "Test suite not yet implemented"