git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
More Haddock comments
1cb455bPhil Freeman
purescript.cabal+1−1
@@ -1,5 +1,5 @@
1name: purescript
1name: purescript
2−version: 0.3.3
2+version: 0.3.4
3cabal-version: >=1.8
3cabal-version: >=1.8
4build-type: Simple
4build-type: Simple
5license: MIT
5license: MIT
src/Language/PureScript/CodeGen/Externs.hs+4
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- This module generates code for \"externs\" files, i.e. files containing only foreign import declarations.
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -24,6 +25,9 @@ import Language.PureScript.Pretty
24import Language.PureScript.Names
25import Language.PureScript.Names
25import Data.List (intercalate)
26import Data.List (intercalate)
26
27
28+-- |
29+-- Generate foreign imports for all declarations in a module
30+--
27moduleToPs :: Module -> Environment -> String
31moduleToPs :: Module -> Environment -> String
28moduleToPs (Module pname@(ProperName moduleName) decls) env =
32moduleToPs (Module pname@(ProperName moduleName) decls) env =
29 "module " ++ moduleName ++ " where\n" ++
33 "module " ++ moduleName ++ " where\n" ++
src/Language/PureScript/CodeGen/JS.hs+7
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- This module generates code in the simplified Javascript intermediate representation from Purescript code
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -41,6 +42,9 @@ import Language.PureScript.CodeGen.JS.AST as AST
41import Language.PureScript.Types
42import Language.PureScript.Types
42import Language.PureScript.CodeGen.Optimize
43import Language.PureScript.CodeGen.Optimize
43
44
45+-- |
46+-- Generate code in the simplified Javascript intermediate representation for all declarations in a module
47+--
44moduleToJs :: Options -> Module -> Environment -> [JS]
48moduleToJs :: Options -> Module -> Environment -> [JS]
45moduleToJs opts (Module pname@(ProperName name) decls) env =
49moduleToJs opts (Module pname@(ProperName name) decls) env =
46 mapMaybe filterRawDecls decls ++
50 mapMaybe filterRawDecls decls ++
@@ -58,6 +62,9 @@ moduleToJs opts (Module pname@(ProperName name) decls) env =
58 typeClassesLast _ (ExternDeclaration TypeClassDictionaryImport _ _ _) = LT
62 typeClassesLast _ (ExternDeclaration TypeClassDictionaryImport _ _ _) = LT
59 typeClassesLast _ _ = EQ
63 typeClassesLast _ _ = EQ
60
64
65+-- |
66+-- Generate code in the simplified Javascript intermediate representation for a declaration
67+--
61declToJs :: Options -> ModuleName -> Declaration -> Environment -> Maybe [JS]
68declToJs :: Options -> ModuleName -> Declaration -> Environment -> Maybe [JS]
62declToJs opts mp (ValueDeclaration ident _ _ val) e =
69declToJs opts mp (ValueDeclaration ident _ _ val) e =
63 Just [ JSVariableIntroduction ident (Just (valueToJs opts mp e val)),
70 Just [ JSVariableIntroduction ident (Just (valueToJs opts mp e val)),
src/Language/PureScript/CodeGen/JS/AST.hs+91−2
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- Data types for the intermediate simplified-Javascript AST
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -21,36 +22,124 @@ import Language.PureScript.Values
21
22
22import Data.Data
23import Data.Data
23
24
25+-- |
26+-- Data type for simplified Javascript expressions
27+--
24data JS
28data JS
29+ -- |
30+ -- A numeric literal
31+ --
25 = JSNumericLiteral (Either Integer Double)
32 = JSNumericLiteral (Either Integer Double)
33+ -- |
34+ -- A string literal
35+ --
26 | JSStringLiteral String
36 | JSStringLiteral String
37+ -- |
38+ -- A boolean literal
39+ --
27 | JSBooleanLiteral Bool
40 | JSBooleanLiteral Bool
41+ -- |
42+ -- A unary operator application
43+ --
28 | JSUnary UnaryOperator JS
44 | JSUnary UnaryOperator JS
45+ -- |
46+ -- A binary operator application
47+ --
29 | JSBinary BinaryOperator JS JS
48 | JSBinary BinaryOperator JS JS
49+ -- |
50+ -- An array literal
51+ --
30 | JSArrayLiteral [JS]
52 | JSArrayLiteral [JS]
53+ -- |
54+ -- An array indexer expression
55+ --
31 | JSIndexer JS JS
56 | JSIndexer JS JS
57+ -- |
58+ -- An object literal
59+ --
32 | JSObjectLiteral [(String, JS)]
60 | JSObjectLiteral [(String, JS)]
61+ -- |
62+ -- An object property accessor expression
63+ --
33 | JSAccessor String JS
64 | JSAccessor String JS
65+ -- |
66+ -- A function introduction (optional name, arguments, body)
67+ --
34 | JSFunction (Maybe Ident) [Ident] JS
68 | JSFunction (Maybe Ident) [Ident] JS
69+ -- |
70+ -- Function application
71+ --
35 | JSApp JS [JS]
72 | JSApp JS [JS]
73+ -- |
74+ -- Variable
75+ --
36 | JSVar Ident
76 | JSVar Ident
77+ -- |
78+ -- Conditional expression
79+ --
37 | JSConditional JS JS JS
80 | JSConditional JS JS JS
81+ -- |
82+ -- A block of expressions in braces
83+ --
38 | JSBlock [JS]
84 | JSBlock [JS]
85+ -- |
86+ -- A variable introduction and optional initialization
87+ --
39 | JSVariableIntroduction Ident (Maybe JS)
88 | JSVariableIntroduction Ident (Maybe JS)
89+ -- |
90+ -- A variable assignment
91+ --
40 | JSAssignment JSAssignment JS
92 | JSAssignment JSAssignment JS
93+ -- |
94+ -- While loop
95+ --
41 | JSWhile JS JS
96 | JSWhile JS JS
97+ -- |
98+ -- For loop
99+ --
42 | JSFor Ident JS JS JS
100 | JSFor Ident JS JS JS
101+ -- |
102+ -- If-then-else statement
103+ --
43 | JSIfElse JS JS (Maybe JS)
104 | JSIfElse JS JS (Maybe JS)
105+ -- |
106+ -- Return statement
107+ --
44 | JSReturn JS
108 | JSReturn JS
109+ -- |
110+ -- Throw statement
111+ --
45 | JSThrow JS
112 | JSThrow JS
113+ -- |
114+ -- Type-Of operator
115+ --
46 | JSTypeOf JS
116 | JSTypeOf JS
117+ -- |
118+ -- Labelled statement
119+ --
47 | JSLabel String JS
120 | JSLabel String JS
121+ -- |
122+ -- Break statement
123+ --
48 | JSBreak String
124 | JSBreak String
125+ -- |
126+ -- Continue statement
127+ --
49 | JSContinue String
128 | JSContinue String
129+ -- |
130+ -- Raw Javascript (generated when parsing fails for an inline foreign import declaration)
131+ --
50 | JSRaw String deriving (Show, Data, Typeable)
132 | JSRaw String deriving (Show, Data, Typeable)
51
133
134+-- |
135+-- Data type for expressions which can appear on the left hand side of an assignment
136+--
52data JSAssignment
137data JSAssignment
138+ -- |
139+ -- Assign a variable
140+ --
53 = JSAssignVariable Ident
141 = JSAssignVariable Ident
142+ -- |
143+ -- Assign an object property
144+ --
54 | JSAssignProperty String JSAssignment deriving (Show, Data, Typeable)
145 | JSAssignProperty String JSAssignment deriving (Show, Data, Typeable)
55−
56−
src/Language/PureScript/CodeGen/Monad.hs+12
@@ -9,6 +9,9 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- Code generation monad
13+--
14+-- This monad provides a supply of fresh names which can be used to create variables.
12--
15--
13-----------------------------------------------------------------------------
16-----------------------------------------------------------------------------
14
17
@@ -20,11 +23,20 @@ import Control.Monad.State
20import Control.Applicative
23import Control.Applicative
21import Language.PureScript.Names
24import Language.PureScript.Names
22
25
26+-- |
27+-- Code generation monad data type
28+--
23newtype Gen a = Gen { unGen :: State [Ident] a } deriving (Functor, Applicative, Monad, MonadState [Ident])
29newtype Gen a = Gen { unGen :: State [Ident] a } deriving (Functor, Applicative, Monad, MonadState [Ident])
24
30
31+-- |
32+-- Run a computation in the code generation monad
33+--
25runGen :: [Ident] -> Gen a -> a
34runGen :: [Ident] -> Gen a -> a
26runGen names = flip evalState names . unGen
35runGen names = flip evalState names . unGen
27
36
37+-- |
38+-- Generate a fresh name
39+--
28fresh :: Gen Ident
40fresh :: Gen Ident
29fresh = do
41fresh = do
30 (s:ss) <- get
42 (s:ss) <- get
src/Language/PureScript/CodeGen/Optimize.hs+20
@@ -9,6 +9,23 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- This module optimizes code in the simplified-Javascript intermediate representation.
13+--
14+-- The following optimizations are supported:
15+--
16+-- * Collapsing nested blocks
17+--
18+-- * Tail call elimination
19+--
20+-- * Inlining of (>>=) and ret for the Eff monad
21+--
22+-- * Removal of unused variables
23+--
24+-- * Removal of unnecessary thunks
25+--
26+-- * Eta conversion
27+--
28+-- * Inlining variables
12--
29--
13-----------------------------------------------------------------------------
30-----------------------------------------------------------------------------
14
31
@@ -28,6 +45,9 @@ import Language.PureScript.Sugar.TypeClasses
28 (mkDictionaryValueName)
45 (mkDictionaryValueName)
29import Language.PureScript.Types (Type(..))
46import Language.PureScript.Types (Type(..))
30
47
48+-- |
49+-- Apply a series of optimizer passes to simplified Javascript code
50+--
31optimize :: Options -> JS -> JS
51optimize :: Options -> JS -> JS
32optimize opts =
52optimize opts =
33 collapseNestedBlocks
53 collapseNestedBlocks
src/Language/PureScript/Parser/Common.hs+165−20
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- Constants, and utility functions to be used when parsing
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -25,6 +26,9 @@ import qualified Text.Parsec.Token as PT
25
26
26import Language.PureScript.Names
27import Language.PureScript.Names
27
28
29+-- |
30+-- A list of reserved identifiers
31+--
28reservedNames :: [String]
32reservedNames :: [String]
29reservedNames = [ "case"
33reservedNames = [ "case"
30 , "of"
34 , "of"
@@ -76,28 +80,52 @@ reservedNames = [ "case"
76 , "instance"
80 , "instance"
77 , "where" ]
81 , "where" ]
78
82
83+-- |
84+-- A list of built-in operator names
85+--
79builtInOperators :: [String]
86builtInOperators :: [String]
80builtInOperators = [ "~", "-", "<=", ">=", "<", ">", "*", "/", "%", "++", "+", "<<", ">>>", ">>"
87builtInOperators = [ "~", "-", "<=", ">=", "<", ">", "*", "/", "%", "++", "+", "<<", ">>>", ">>"
81 , "==", "!=", "&&", "||", "&", "^", "|", "!!", "!" ]
88 , "==", "!=", "&&", "||", "&", "^", "|", "!!", "!" ]
82
89
90+-- |
91+-- A list of reserved operators
92+--
83reservedOpNames :: [String]
93reservedOpNames :: [String]
84reservedOpNames = builtInOperators ++ [ "=>", "->", "=", ".", "\\" ]
94reservedOpNames = builtInOperators ++ [ "=>", "->", "=", ".", "\\" ]
85
95
96+-- |
97+-- Valid first characters for an identifier
98+--
86identStart :: P.Parsec String u Char
99identStart :: P.Parsec String u Char
87identStart = P.lower <|> P.oneOf "_"
100identStart = P.lower <|> P.oneOf "_"
88
101
102+-- |
103+-- Valid first characters for a proper name
104+--
89properNameStart :: P.Parsec String u Char
105properNameStart :: P.Parsec String u Char
90properNameStart = P.upper
106properNameStart = P.upper
91
107
108+-- |
109+-- Valid identifier characters
110+--
92identLetter :: P.Parsec String u Char
111identLetter :: P.Parsec String u Char
93identLetter = P.alphaNum <|> P.oneOf "_'"
112identLetter = P.alphaNum <|> P.oneOf "_'"
94
113
114+-- |
115+-- Valid first characters for an operator
116+--
95opStart :: P.Parsec String u Char
117opStart :: P.Parsec String u Char
96opStart = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
118opStart = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
97
119
120+-- |
121+-- Valid operators characters
122+--
98opLetter :: P.Parsec String u Char
123opLetter :: P.Parsec String u Char
99opLetter = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
124opLetter = P.oneOf ":!#$%&*+./<=>?@\\^|-~"
100
125
126+-- |
127+-- The PureScript language definition
128+--
101langDef :: PT.GenLanguageDef String u Identity
129langDef :: PT.GenLanguageDef String u Identity
102langDef = PT.LanguageDef
130langDef = PT.LanguageDef
103 { PT.reservedNames = reservedNames
131 { PT.reservedNames = reservedNames
@@ -113,104 +141,209 @@ langDef = PT.LanguageDef
113 , PT.caseSensitive = True
141 , PT.caseSensitive = True
114 }
142 }
115
143
144+-- |
145+-- A token parser based on the language definition
146+--
116tokenParser :: PT.GenTokenParser String u Identity
147tokenParser :: PT.GenTokenParser String u Identity
117tokenParser = PT.makeTokenParser langDef
148tokenParser = PT.makeTokenParser langDef
118
149
150+-- |
151+-- Parse a token
152+--
119lexeme :: P.Parsec String u a -> P.Parsec String u a
153lexeme :: P.Parsec String u a -> P.Parsec String u a
120lexeme = PT.lexeme tokenParser
154lexeme = PT.lexeme tokenParser
121
155
156+-- |
157+-- Parse an identifier
158+--
122identifier :: P.Parsec String u String
159identifier :: P.Parsec String u String
123identifier = PT.identifier tokenParser
160identifier = PT.identifier tokenParser
124
161
162+-- |
163+-- Parse a reserved word
164+--
125reserved :: String -> P.Parsec String u ()
165reserved :: String -> P.Parsec String u ()
126reserved = PT.reserved tokenParser
166reserved = PT.reserved tokenParser
127
167
168+-- |
169+-- Parse a reserved operator
170+--
128reservedOp :: String -> P.Parsec String u ()
171reservedOp :: String -> P.Parsec String u ()
129reservedOp = PT.reservedOp tokenParser
172reservedOp = PT.reservedOp tokenParser
130
173
174+-- |
175+-- Parse an operator
176+--
131operator :: P.Parsec String u String
177operator :: P.Parsec String u String
132operator = PT.operator tokenParser
178operator = PT.operator tokenParser
133
179
180+-- |
181+-- Parse a string literal
182+--
134stringLiteral :: P.Parsec String u String
183stringLiteral :: P.Parsec String u String
135stringLiteral = PT.stringLiteral tokenParser
184stringLiteral = PT.stringLiteral tokenParser
136
185
186+-- |
187+-- Parse whitespace
188+--
137whiteSpace :: P.Parsec String u ()
189whiteSpace :: P.Parsec String u ()
138whiteSpace = PT.whiteSpace tokenParser
190whiteSpace = PT.whiteSpace tokenParser
139
191
192+-- |
193+-- Semicolon
194+--
140semi :: P.Parsec String u String
195semi :: P.Parsec String u String
141semi = PT.semi tokenParser
196semi = PT.semi tokenParser
142
197
198+-- |
199+-- Colon
200+--
143colon :: P.Parsec String u String
201colon :: P.Parsec String u String
144colon = PT.colon tokenParser
202colon = PT.colon tokenParser
145
203
204+-- |
205+-- Period
206+--
146dot :: P.Parsec String u String
207dot :: P.Parsec String u String
147dot = PT.dot tokenParser
208dot = PT.dot tokenParser
148
209
210+-- |
211+-- Comma
212+--
149comma :: P.Parsec String u String
213comma :: P.Parsec String u String
150comma = PT.comma tokenParser
214comma = PT.comma tokenParser
151
215
216+-- |
217+-- Backtick
218+--
152tick :: P.Parsec String u Char
219tick :: P.Parsec String u Char
153tick = lexeme $ P.char '`'
220tick = lexeme $ P.char '`'
154
221
222+-- |
223+-- Pipe character
224+--
155pipe :: P.Parsec String u Char
225pipe :: P.Parsec String u Char
156pipe = lexeme $ P.char '|'
226pipe = lexeme $ P.char '|'
157
227
228+-- |
229+-- Natural number
230+--
158natural :: P.Parsec String u Integer
231natural :: P.Parsec String u Integer
159natural = PT.natural tokenParser
232natural = PT.natural tokenParser
160
233
234+-- |
235+-- Parse a proper name
236+--
237+properName :: P.Parsec String u ProperName
238+properName = lexeme $ ProperName <$> P.try ((:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name")
239+
240+-- |
241+-- Parse a qualified name, i.e. M.name or just name
242+--
243+parseQualified :: P.Parsec String ParseState a -> P.Parsec String ParseState (Qualified a)
244+parseQualified parser = qual
245+ where
246+ qual = (Qualified <$> (Just . ModuleName <$> P.try (properName <* delimiter)) <*> parser)
247+ <|> (Qualified Nothing <$> P.try parser)
248+ delimiter = indented *> dot
249+
250+-- |
251+-- Parse an integer or floating point value
252+--
253+integerOrFloat :: P.Parsec String u (Either Integer Double)
254+integerOrFloat = (Left <$> P.try (PT.natural tokenParser) <|>
255+ Right <$> P.try (PT.float tokenParser)) P.<?> "number"
256+
257+-- |
258+-- Parse an operator or a built-in operator
259+--
260+operatorOrBuiltIn :: P.Parsec String u String
261+operatorOrBuiltIn = P.try operator <|> P.choice (map (\s -> P.try (reservedOp s) >> return s) builtInOperators)
262+
263+-- |
264+-- Parse an identifier or parenthesized operator
265+--
266+parseIdent :: P.Parsec String ParseState Ident
267+parseIdent = (Ident <$> identifier) <|> (Op <$> parens operatorOrBuiltIn)
268+
269+-- |
270+-- Parse a token inside square brackets
271+--
161squares :: P.Parsec String ParseState a -> P.Parsec String ParseState a
272squares :: P.Parsec String ParseState a -> P.Parsec String ParseState a
162squares = P.between (lexeme $ P.char '[') (lexeme $ indented *> P.char ']') . (indented *>)
273squares = P.between (lexeme $ P.char '[') (lexeme $ indented *> P.char ']') . (indented *>)
163
274
275+-- |
276+-- Parse a token inside parentheses
277+--
164parens :: P.Parsec String ParseState a -> P.Parsec String ParseState a
278parens :: P.Parsec String ParseState a -> P.Parsec String ParseState a
165parens = P.between (lexeme $ P.char '(') (lexeme $ indented *> P.char ')') . (indented *>)
279parens = P.between (lexeme $ P.char '(') (lexeme $ indented *> P.char ')') . (indented *>)
166
280
281+-- |
282+-- Parse a token inside braces
283+--
167braces :: P.Parsec String ParseState a -> P.Parsec String ParseState a
284braces :: P.Parsec String ParseState a -> P.Parsec String ParseState a
168braces = P.between (lexeme $ P.char '{') (lexeme $ indented *> P.char '}') . (indented *>)
285braces = P.between (lexeme $ P.char '{') (lexeme $ indented *> P.char '}') . (indented *>)
169
286
287+-- |
288+-- Parse a token inside angle brackets
289+--
170angles :: P.Parsec String ParseState a -> P.Parsec String ParseState a
290angles :: P.Parsec String ParseState a -> P.Parsec String ParseState a
171angles = P.between (lexeme $ P.char '<') (lexeme $ indented *> P.char '>') . (indented *>)
291angles = P.between (lexeme $ P.char '<') (lexeme $ indented *> P.char '>') . (indented *>)
172
292
293+-- |
294+-- Parse zero or more values separated by a separator token
295+--
173sepBy :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
296sepBy :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
174sepBy p s = P.sepBy (indented *> p) (indented *> s)
297sepBy p s = P.sepBy (indented *> p) (indented *> s)
175
298
299+-- |
300+-- Parse one or more values separated by a separator token
301+--
176sepBy1 :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
302sepBy1 :: P.Parsec String ParseState a -> P.Parsec String ParseState sep -> P.Parsec String ParseState [a]
177sepBy1 p s = P.sepBy1 (indented *> p) (indented *> s)
303sepBy1 p s = P.sepBy1 (indented *> p) (indented *> s)
178
304
305+-- |
306+-- Parse zero or more values separated by semicolons
307+--
179semiSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
308semiSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
180semiSep = flip sepBy semi
309semiSep = flip sepBy semi
181
310
311+-- |
312+-- Parse one or more values separated by semicolons
313+--
182semiSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
314semiSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
183semiSep1 = flip sepBy1 semi
315semiSep1 = flip sepBy1 semi
184
316
317+-- |
318+-- Parse zero or more values separated by commas
319+--
185commaSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
320commaSep :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
186commaSep = flip sepBy comma
321commaSep = flip sepBy comma
187
322
323+-- |
324+-- Parse one or more values separated by commas
325+--
188commaSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
326commaSep1 :: P.Parsec String ParseState a -> P.Parsec String ParseState [a]
189commaSep1 = flip sepBy1 comma
327commaSep1 = flip sepBy1 comma
190
328
191−properName :: P.Parsec String u ProperName
329+-- |
192−properName = lexeme $ ProperName <$> P.try ((:) <$> P.upper <*> many (PT.identLetter langDef) P.<?> "name")
330+-- Run the first parser, then match the second if possible, applying the specified function on a successful match
193−
331+--
194−parseQualified :: P.Parsec String ParseState a -> P.Parsec String ParseState (Qualified a)
195−parseQualified parser = qual
196− where
197− qual = (Qualified <$> (Just . ModuleName <$> P.try (properName <* delimiter)) <*> parser)
198− <|> (Qualified Nothing <$> P.try parser)
199− delimiter = indented *> dot
200−
201−integerOrFloat :: P.Parsec String u (Either Integer Double)
202−integerOrFloat = (Left <$> P.try (PT.natural tokenParser) <|>
203− Right <$> P.try (PT.float tokenParser)) P.<?> "number"
204−
205augment :: 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
332augment :: 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
206augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q
333augment p q f = flip (maybe id $ flip f) <$> p <*> P.optionMaybe q
207
334
335+-- |
336+-- Run the first parser, then match the second zero or more times, applying the specified function for each match
337+--
208fold :: 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
338fold :: 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
209fold first more combine = do
339fold first more combine = do
210 a <- first
340 a <- first
211 bs <- P.many more
341 bs <- P.many more
212 return $ foldl combine a bs
342 return $ foldl combine a bs
213
343
344+-- |
345+-- Build a parser from a smaller parser and a list of parsers for postfix operators
346+--
214buildPostfixParser :: P.Stream s m t => [a -> P.ParsecT s u m a] -> P.ParsecT s u m a -> P.ParsecT s u m a
347buildPostfixParser :: P.Stream s m t => [a -> P.ParsecT s u m a] -> P.ParsecT s u m a -> P.ParsecT s u m a
215buildPostfixParser fs first = do
348buildPostfixParser fs first = do
216 a <- first
349 a <- first
@@ -222,15 +355,15 @@ buildPostfixParser fs first = do
222 Nothing -> return a
355 Nothing -> return a
223 Just a' -> go a'
356 Just a' -> go a'
224
357
225−operatorOrBuiltIn :: P.Parsec String u String
358+-- |
226−operatorOrBuiltIn = P.try operator <|> P.choice (map (\s -> P.try (reservedOp s) >> return s) builtInOperators)
359+-- Parse an identifier in backticks or an operator
227−
360+--
228−parseIdent :: P.Parsec String ParseState Ident
229−parseIdent = (Ident <$> identifier) <|> (Op <$> parens operatorOrBuiltIn)
230−
231parseIdentInfix :: P.Parsec String ParseState (Qualified Ident)
361parseIdentInfix :: P.Parsec String ParseState (Qualified Ident)
232parseIdentInfix = (P.between tick tick (parseQualified (Ident <$> identifier))) <|> parseQualified (Op <$> operatorOrBuiltIn)
362parseIdentInfix = (P.between tick tick (parseQualified (Ident <$> identifier))) <|> parseQualified (Op <$> operatorOrBuiltIn)
233
363
364+-- |
365+-- Mark the current indentation level
366+--
234mark :: P.Parsec String ParseState a -> P.Parsec String ParseState a
367mark :: P.Parsec String ParseState a -> P.Parsec String ParseState a
235mark p = do
368mark p = do
236 current <- indentationLevel <$> P.getState
369 current <- indentationLevel <$> P.getState
@@ -240,17 +373,29 @@ mark p = do
240 P.modifyState $ \st -> st { indentationLevel = current }
373 P.modifyState $ \st -> st { indentationLevel = current }
241 return a
374 return a
242
375
376+-- |
377+-- Check that the current identation level matches a predicate
378+--
243checkIndentation :: (P.Column -> P.Column -> Bool) -> P.Parsec String ParseState ()
379checkIndentation :: (P.Column -> P.Column -> Bool) -> P.Parsec String ParseState ()
244checkIndentation rel = do
380checkIndentation rel = do
245 col <- P.sourceColumn <$> P.getPosition
381 col <- P.sourceColumn <$> P.getPosition
246 current <- indentationLevel <$> P.getState
382 current <- indentationLevel <$> P.getState
247 guard (col `rel` current)
383 guard (col `rel` current)
248
384
385+-- |
386+-- Check that the current indentation level is past the current mark
387+--
249indented :: P.Parsec String ParseState ()
388indented :: P.Parsec String ParseState ()
250indented = checkIndentation (>) P.<?> "indentation"
389indented = checkIndentation (>) P.<?> "indentation"
251
390
391+-- |
392+-- Check that the current indentation level is at the same indentation as the current mark
393+--
252same :: P.Parsec String ParseState ()
394same :: P.Parsec String ParseState ()
253same = checkIndentation (==) P.<?> "no indentation"
395same = checkIndentation (==) P.<?> "no indentation"
254
396
397+-- |
398+-- Run a parser which supports indentation
399+--
255runIndentParser :: P.Parsec String ParseState a -> String -> Either P.ParseError a
400runIndentParser :: P.Parsec String ParseState a -> String -> Either P.ParseError a
256runIndentParser p = P.runParser p (ParseState 0) ""
401runIndentParser p = P.runParser p (ParseState 0) ""
src/Language/PureScript/Parser/Declarations.hs+10
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- Parsers for module definitions and declarations
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -120,6 +121,9 @@ parseTypeInstanceDeclaration = do
120 members <- mark (P.many (same *> parseValueDeclaration))
121 members <- mark (P.many (same *> parseValueDeclaration))
121 return $ TypeInstanceDeclaration (fromMaybe [] deps) className ty members
122 return $ TypeInstanceDeclaration (fromMaybe [] deps) className ty members
122
123
124+-- |
125+-- Parse a single declaration
126+--
123parseDeclaration :: P.Parsec String ParseState Declaration
127parseDeclaration :: P.Parsec String ParseState Declaration
124parseDeclaration = P.choice
128parseDeclaration = P.choice
125 [ parseDataDeclaration
129 [ parseDataDeclaration
@@ -132,6 +136,9 @@ parseDeclaration = P.choice
132 , parseTypeClassDeclaration
136 , parseTypeClassDeclaration
133 , parseTypeInstanceDeclaration ] P.<?> "declaration"
137 , parseTypeInstanceDeclaration ] P.<?> "declaration"
134
138
139+-- |
140+-- Parse a module header and a collection of declarations
141+--
135parseModule :: P.Parsec String ParseState Module
142parseModule :: P.Parsec String ParseState Module
136parseModule = do
143parseModule = do
137 reserved "module"
144 reserved "module"
@@ -141,5 +148,8 @@ parseModule = do
141 decls <- mark (P.many (same *> parseDeclaration))
148 decls <- mark (P.many (same *> parseDeclaration))
142 return $ Module name decls
149 return $ Module name decls
143
150
151+-- |
152+-- Parse a collection of modules
153+--
144parseModules :: P.Parsec String ParseState [Module]
154parseModules :: P.Parsec String ParseState [Module]
145parseModules = whiteSpace *> mark (P.many (same *> parseModule)) <* P.eof
155parseModules = whiteSpace *> mark (P.many (same *> parseModule)) <* P.eof
src/Language/PureScript/Parser/JS.hs+4
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- A parser for a small fragment of Javascript
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -99,6 +100,9 @@ binary op s f = P.Infix (P.try $ C.reservedOp s >> return (JSBinary op)) f
99unary :: UnaryOperator -> String -> P.Operator String u Identity JS
100unary :: UnaryOperator -> String -> P.Operator String u Identity JS
100unary op s = P.Prefix (P.try $ C.reservedOp s >> return (JSUnary op))
101unary op s = P.Prefix (P.try $ C.reservedOp s >> return (JSUnary op))
101
102
103+-- |
104+-- Parse a simplified Javascript expression
105+--
102parseJS :: P.Parsec String u JS
106parseJS :: P.Parsec String u JS
103parseJS =
107parseJS =
104 (P.buildExpressionParser operators
108 (P.buildExpressionParser operators
src/Language/PureScript/Parser/Kinds.hs+4−1
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- A parser for kinds
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -34,7 +35,9 @@ parseTypeAtom = indented *> P.choice (map P.try
34 [ parseStar
35 [ parseStar
35 , parseBang
36 , parseBang
36 , parens parseKind ])
37 , parens parseKind ])
37−
38+-- |
39+-- Parse a kind
40+--
38parseKind :: P.Parsec String ParseState Kind
41parseKind :: P.Parsec String ParseState Kind
39parseKind = P.buildExpressionParser operators parseTypeAtom P.<?> "kind"
42parseKind = P.buildExpressionParser operators parseTypeAtom P.<?> "kind"
40 where
43 where
src/Language/PureScript/Parser/State.hs+10−2
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- State for the parser monad
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -16,7 +17,14 @@ module Language.PureScript.Parser.State where
16
17
17import qualified Text.Parsec as P
18import qualified Text.Parsec as P
18
19
20+-- |
21+-- State for the parser monad
22+--
19−data ParseState = ParseState
23+data ParseState = ParseState {
24+ -- |
25+ -- The most recently marked indentation level
26+ --
20− { indentationLevel :: P.Column } deriving Show
27+ indentationLevel :: P.Column
28+ } deriving Show
21
29
22
30
src/Language/PureScript/Parser/Types.hs+8−2
@@ -9,13 +9,13 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- Parsers for types
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
15module Language.PureScript.Parser.Types (
16module Language.PureScript.Parser.Types (
16 parseType,
17 parseType,
17− parsePolyType,
18+ parsePolyType
18− parseRow
19) where
19) where
20
20
21import Language.PureScript.Types
21import Language.PureScript.Types
@@ -97,12 +97,18 @@ parseAnyType = (P.buildExpressionParser operators . buildPostfixParser postfixTa
97 postfixTable = [ \x -> TypeApp x <$> P.try (indented *> parseTypeAtom) ]
97 postfixTable = [ \x -> TypeApp x <$> P.try (indented *> parseTypeAtom) ]
98 operators = [ [ P.Infix (lexeme (P.try (P.string "->")) >> return (\t1 t2 -> Function [t1] t2)) P.AssocRight ] ]
98 operators = [ [ P.Infix (lexeme (P.try (P.string "->")) >> return (\t1 t2 -> Function [t1] t2)) P.AssocRight ] ]
99
99
100+-- |
101+-- Parse a monotype
102+--
100parseType :: P.Parsec String ParseState Type
103parseType :: P.Parsec String ParseState Type
101parseType = do
104parseType = do
102 ty <- parseAnyType
105 ty <- parseAnyType
103 unless (isMonoType ty) $ P.unexpected "polymorphic type"
106 unless (isMonoType ty) $ P.unexpected "polymorphic type"
104 return ty
107 return ty
105
108
109+-- |
110+-- Parse a polytype
111+--
106parsePolyType :: P.Parsec String ParseState Type
112parsePolyType :: P.Parsec String ParseState Type
107parsePolyType = do
113parsePolyType = do
108 ty <- parseAnyType
114 ty <- parseAnyType
src/Language/PureScript/Parser/Values.hs+17−2
@@ -9,15 +9,16 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- Parsers for values, statements, binders and guards
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
15module Language.PureScript.Parser.Values (
16module Language.PureScript.Parser.Values (
16 parseValue,
17 parseValue,
18+ parseStatement,
17 parseGuard,
19 parseGuard,
18 parseBinder,
20 parseBinder,
19 parseBinderNoParens,
21 parseBinderNoParens,
20− parseDoNotationElement
21) where
22) where
22
23
23import Language.PureScript.Values
24import Language.PureScript.Values
@@ -146,6 +147,9 @@ parseDoNotationElement = P.choice
146 , parseDoNotationLet
147 , parseDoNotationLet
147 , P.try (DoNotationValue <$> parseValue) ]
148 , P.try (DoNotationValue <$> parseValue) ]
148
149
150+-- |
151+-- Parse a value
152+--
149parseValue :: P.Parsec String ParseState Value
153parseValue :: P.Parsec String ParseState Value
150parseValue =
154parseValue =
151 (buildExpressionParser operators
155 (buildExpressionParser operators
@@ -212,6 +216,9 @@ parseElseStatement = C.reserved "else" >> (ElseIf <$> parseIfStatement
212parseReturn :: P.Parsec String ParseState Statement
216parseReturn :: P.Parsec String ParseState Statement
213parseReturn = Return <$> (C.reserved "return" *> parseValue <* C.indented <* C.semi)
217parseReturn = Return <$> (C.reserved "return" *> parseValue <* C.indented <* C.semi)
214
218
219+-- |
220+-- Parse a statement
221+--
215parseStatement :: P.Parsec String ParseState Statement
222parseStatement :: P.Parsec String ParseState Statement
216parseStatement = P.choice
223parseStatement = P.choice
217 [ parseVariableIntroduction
224 [ parseVariableIntroduction
@@ -273,11 +280,17 @@ parseBinderAtom = P.choice (map P.try
273 , parseArrayBinder
280 , parseArrayBinder
274 , C.parens parseBinder ]) P.<?> "binder"
281 , C.parens parseBinder ]) P.<?> "binder"
275
282
283+-- |
284+-- Parse a binder
285+--
276parseBinder :: P.Parsec String ParseState Binder
286parseBinder :: P.Parsec String ParseState Binder
277parseBinder = (buildExpressionParser operators parseBinderAtom) P.<?> "expression"
287parseBinder = (buildExpressionParser operators parseBinderAtom) P.<?> "expression"
278 where
288 where
279 operators = [ [ Infix ( C.lexeme (P.try $ C.indented *> C.reservedOp ":") >> return ConsBinder) AssocRight ] ]
289 operators = [ [ Infix ( C.lexeme (P.try $ C.indented *> C.reservedOp ":") >> return ConsBinder) AssocRight ] ]
280
290
291+-- |
292+-- Parse a binder as it would appear in a top level declaration
293+--
281parseBinderNoParens :: P.Parsec String ParseState Binder
294parseBinderNoParens :: P.Parsec String ParseState Binder
282parseBinderNoParens = P.choice (map P.try
295parseBinderNoParens = P.choice (map P.try
283 [ parseNullBinder
296 [ parseNullBinder
@@ -290,7 +303,9 @@ parseBinderNoParens = P.choice (map P.try
290 , parseObjectBinder
303 , parseObjectBinder
291 , parseArrayBinder
304 , parseArrayBinder
292 , C.parens parseBinder ]) P.<?> "binder"
305 , C.parens parseBinder ]) P.<?> "binder"
293−
306+-- |
307+-- Parse a guard
308+--
294parseGuard :: P.Parsec String ParseState Guard
309parseGuard :: P.Parsec String ParseState Guard
295parseGuard = C.indented *> C.pipe *> C.indented *> parseValue
310parseGuard = C.indented *> C.pipe *> C.indented *> parseValue
296
311
src/Language/PureScript/Sugar/BindingGroups.hs+14
@@ -9,6 +9,8 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- This module implements the desugaring pass which creates binding groups from sets of
13+-- mutually-recursive value declarations and mutually-recursive type declarations.
12--
14--
13-----------------------------------------------------------------------------
15-----------------------------------------------------------------------------
14
16
@@ -30,12 +32,21 @@ import Language.PureScript.Names
30import Language.PureScript.Values
32import Language.PureScript.Values
31import Language.PureScript.Types
33import Language.PureScript.Types
32
34
35+-- |
36+-- Replace all sets of mutually-recursive declarations in a module with binding groups
37+--
33createBindingGroupsModule :: [Module] -> Either String [Module]
38createBindingGroupsModule :: [Module] -> Either String [Module]
34createBindingGroupsModule = mapM $ \(Module name ds) -> Module name <$> createBindingGroups ds
39createBindingGroupsModule = mapM $ \(Module name ds) -> Module name <$> createBindingGroups ds
35
40
41+-- |
42+-- Collapse all binding groups in a module to individual declarations
43+--
36collapseBindingGroupsModule :: [Module] -> [Module]
44collapseBindingGroupsModule :: [Module] -> [Module]
37collapseBindingGroupsModule = map $ \(Module name ds) -> Module name (collapseBindingGroups ds)
45collapseBindingGroupsModule = map $ \(Module name ds) -> Module name (collapseBindingGroups ds)
38
46
47+-- |
48+-- Replace all sets of mutually-recursive declarations with binding groups
49+--
39createBindingGroups :: [Declaration] -> Either String [Declaration]
50createBindingGroups :: [Declaration] -> Either String [Declaration]
40createBindingGroups ds = do
51createBindingGroups ds = do
41 let values = filter isValueDecl ds
52 let values = filter isValueDecl ds
@@ -54,6 +65,9 @@ createBindingGroups ds = do
54 filter isExternDecl ds ++
65 filter isExternDecl ds ++
55 bindingGroupDecls
66 bindingGroupDecls
56
67
68+-- |
69+-- Collapse all binding groups to individual declarations
70+--
57collapseBindingGroups :: [Declaration] -> [Declaration]
71collapseBindingGroups :: [Declaration] -> [Declaration]
58collapseBindingGroups ds = concatMap go ds
72collapseBindingGroups ds = concatMap go ds
59 where
73 where
src/Language/PureScript/Sugar/CaseDeclarations.hs+8−1
@@ -9,6 +9,8 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- This module implements the desugaring pass which replaces top-level binders with
13+-- case expressions.
12--
14--
13-----------------------------------------------------------------------------
15-----------------------------------------------------------------------------
14
16
@@ -27,9 +29,14 @@ import Language.PureScript.Values
27import Language.PureScript.Declarations
29import Language.PureScript.Declarations
28import Language.PureScript.Scope
30import Language.PureScript.Scope
29
31
32+-- |
33+-- Replace all top-level binders in a module with case expressions.
34+--
30desugarCasesModule :: [Module] -> Either String [Module]
35desugarCasesModule :: [Module] -> Either String [Module]
31desugarCasesModule ms = forM ms $ \(Module name ds) -> Module name <$> desugarCases ds
36desugarCasesModule ms = forM ms $ \(Module name ds) -> Module name <$> desugarCases ds
32−
37+-- |
38+-- Replace all top-level binders with case expressions.
39+--
33desugarCases :: [Declaration] -> Either String [Declaration]
40desugarCases :: [Declaration] -> Either String [Declaration]
34desugarCases = fmap join . mapM toDecls . groupBy inSameGroup
41desugarCases = fmap join . mapM toDecls . groupBy inSameGroup
35
42
src/Language/PureScript/Sugar/DoNotation.hs+6
@@ -9,6 +9,8 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- This module implements the desugaring pass which replaces do-notation statements with
13+-- appropriate calls to (>>=) from the Prelude.Monad type class.
12--
14--
13-----------------------------------------------------------------------------
15-----------------------------------------------------------------------------
14
16
@@ -23,6 +25,10 @@ import Language.PureScript.Values
23import Language.PureScript.Names
25import Language.PureScript.Names
24import Language.PureScript.Scope
26import Language.PureScript.Scope
25
27
28+-- |
29+-- Replace all @DoNotationBind@ and @DoNotationValue@ constructors with applications of the Prelude.(>>=) function,
30+-- and all @DoNotationLet@ constructors with let expressions.
31+--
26desugarDo :: (Data d) => d -> Either String d
32desugarDo :: (Data d) => d -> Either String d
27desugarDo = everywhereM (mkM replace)
33desugarDo = everywhereM (mkM replace)
28 where
34 where
src/Language/PureScript/Sugar/Operators.hs+8
@@ -9,6 +9,11 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- This module implements the desugaring pass which reapplies binary operators based
13+-- on their fixity data and removes explicit parentheses.
14+--
15+-- The value parser ignores fixity data when parsing binary operator applications, so
16+-- it is necessary to reorder them here.
12--
17--
13-----------------------------------------------------------------------------
18-----------------------------------------------------------------------------
14
19
@@ -33,6 +38,9 @@ import qualified Text.Parsec as P
33import qualified Text.Parsec.Pos as P
38import qualified Text.Parsec.Pos as P
34import qualified Text.Parsec.Expr as P
39import qualified Text.Parsec.Expr as P
35
40
41+-- |
42+-- Remove explicit parentheses and reorder binary operator applications
43+--
36rebracket :: [Module] -> Either String [Module]
44rebracket :: [Module] -> Either String [Module]
37rebracket = go M.empty []
45rebracket = go M.empty []
38 where
46 where
src/Language/PureScript/Sugar/TypeClasses.hs+13
@@ -9,6 +9,8 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- This module implements the desugaring pass which creates type synonyms for type class dictionaries
13+-- and dictionary expressions for type class instances.
12--
14--
13-----------------------------------------------------------------------------
15-----------------------------------------------------------------------------
14
16
@@ -38,6 +40,10 @@ type MemberMap = M.Map (ModuleName, ProperName) (String, [(String, Type)])
38
40
39type Desugar = StateT MemberMap (Either String)
41type Desugar = StateT MemberMap (Either String)
40
42
43+-- |
44+-- Add type synonym declarations for type class dictionary types, and value declarations for type class
45+-- instance dictionary expressions.
46+--
41desugarTypeClasses :: [Module] -> Either String [Module]
47desugarTypeClasses :: [Module] -> Either String [Module]
42desugarTypeClasses = flip evalStateT M.empty . mapM desugarModule
48desugarTypeClasses = flip evalStateT M.empty . mapM desugarModule
43
49
@@ -120,6 +126,9 @@ quantify ty' = foldr ForAll ty' tyVars
120 collect (TypeVar v) = [v]
126 collect (TypeVar v) = [v]
121 collect _ = []
127 collect _ = []
122
128
129+-- |
130+-- Generate a name for a type class dictionary, based on the module name, class name and type name
131+--
123mkDictionaryValueName :: ModuleName -> Qualified ProperName -> Type -> Either String Ident
132mkDictionaryValueName :: ModuleName -> Qualified ProperName -> Type -> Either String Ident
124mkDictionaryValueName mn cl ty = do
133mkDictionaryValueName mn cl ty = do
125 tyStr <- typeToString mn ty
134 tyStr <- typeToString mn ty
@@ -135,6 +144,10 @@ typeToString mn (TypeConstructor ty') = return $ qualifiedToString mn ty'
135typeToString mn (TypeApp ty' (TypeVar _)) = typeToString mn ty'
144typeToString mn (TypeApp ty' (TypeVar _)) = typeToString mn ty'
136typeToString a b = Left $ "Type class instance must be of the form T a1 ... an " ++ show (a, b)
145typeToString a b = Left $ "Type class instance must be of the form T a1 ... an " ++ show (a, b)
137
146
147+-- |
148+-- Generate a name for a type class dictionary member, based on the module name, class name, type name and
149+-- member name
150+--
138mkDictionaryEntryName :: ModuleName -> Qualified ProperName -> Type -> Ident -> Desugar Ident
151mkDictionaryEntryName :: ModuleName -> Qualified ProperName -> Type -> Ident -> Desugar Ident
139mkDictionaryEntryName mn name ty ident = do
152mkDictionaryEntryName mn name ty ident = do
140 Ident dictName <- lift $ mkDictionaryValueName mn name ty
153 Ident dictName <- lift $ mkDictionaryValueName mn name ty
src/Language/PureScript/Sugar/TypeDeclarations.hs+8
@@ -9,6 +9,8 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- This module implements the desugaring pass which replaces top-level type declarations with
13+-- type annotations on the corresponding expression.
12--
14--
13-----------------------------------------------------------------------------
15-----------------------------------------------------------------------------
14
16
@@ -24,9 +26,15 @@ import Control.Monad (forM)
24import Language.PureScript.Declarations
26import Language.PureScript.Declarations
25import Language.PureScript.Values
27import Language.PureScript.Values
26
28
29+-- |
30+-- Replace all top level type declarations in a module with type annotations
31+--
27desugarTypeDeclarationsModule :: [Module] -> Either String [Module]
32desugarTypeDeclarationsModule :: [Module] -> Either String [Module]
28desugarTypeDeclarationsModule ms = forM ms $ \(Module name ds) -> Module name <$> desugarTypeDeclarations ds
33desugarTypeDeclarationsModule ms = forM ms $ \(Module name ds) -> Module name <$> desugarTypeDeclarations ds
29
34
35+-- |
36+-- Replace all top level type declarations with type annotations
37+--
30desugarTypeDeclarations :: [Declaration] -> Either String [Declaration]
38desugarTypeDeclarations :: [Declaration] -> Either String [Declaration]
31desugarTypeDeclarations (TypeDeclaration name ty : ValueDeclaration name' [] Nothing val : rest) | name == name' =
39desugarTypeDeclarations (TypeDeclaration name ty : ValueDeclaration name' [] Nothing val : rest) | name == name' =
32 desugarTypeDeclarations (ValueDeclaration name [] Nothing (TypedValue True val ty) : rest)
40 desugarTypeDeclarations (ValueDeclaration name [] Nothing (TypedValue True val ty) : rest)
src/Language/PureScript/TypeChecker.hs+14
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- The top-level type checker, which checks all declarations in a module.
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -88,6 +89,19 @@ addTypeClassDictionaries :: [TypeClassDictionaryInScope] -> Check ()
88addTypeClassDictionaries entries = do
89addTypeClassDictionaries entries = do
89 modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = entries ++ (typeClassDictionaries . checkEnv $ st) } }
90 modify $ \st -> st { checkEnv = (checkEnv st) { typeClassDictionaries = entries ++ (typeClassDictionaries . checkEnv $ st) } }
90
91
92+-- |
93+-- Type check all declarations in a module
94+--
95+-- At this point, many declarations will have been desugared, but it is still necessary to
96+--
97+-- * Kind-check all types and add them to the @Environment@
98+--
99+-- * Type-check all values and add them to the @Environment@
100+--
101+-- * Bring type class instances into scope
102+--
103+-- * Process module imports
104+--
91typeCheckAll :: ModuleName -> [Declaration] -> Check [Declaration]
105typeCheckAll :: ModuleName -> [Declaration] -> Check [Declaration]
92typeCheckAll _ [] = return []
106typeCheckAll _ [] = return []
93typeCheckAll moduleName (d@(DataDeclaration name args dctors) : rest) = do
107typeCheckAll moduleName (d@(DataDeclaration name args dctors) : rest) = do
src/Language/PureScript/TypeChecker/Types.hs+19
@@ -20,6 +20,25 @@ module Language.PureScript.TypeChecker.Types (
20 typesOf
20 typesOf
21) where
21) where
22
22
23+{-
24+ The following functions represent the corresponding type checking judgements:
25+
26+ infer
27+ Synthesize a type for a value
28+
29+ check
30+ Check a value has a given type
31+
32+ checkProperties
33+ Check an object with a given type contains specified properties
34+
35+ checkFunctionApplication
36+ Check a function of a given type returns a value of another type when applied to its arguments
37+
38+ subsumes
39+ Check a type subsumes another type
40+-}
41+
23import Data.List
42import Data.List
24import Data.Maybe (maybeToList, isNothing, isJust, fromMaybe)
43import Data.Maybe (maybeToList, isNothing, isJust, fromMaybe)
25import qualified Data.Data as D
44import qualified Data.Data as D
src/Language/PureScript/Values.hs+277−7
@@ -9,6 +9,7 @@
9-- Portability :
9-- Portability :
10--
10--
11-- |
11-- |
12+-- Data types for values, statements, binders and do notation
12--
13--
13-----------------------------------------------------------------------------
14-----------------------------------------------------------------------------
14
15
@@ -21,100 +22,369 @@ import Language.PureScript.Names
21
22
22import Data.Data
23import Data.Data
23
24
25+-- |
26+-- A guard is just a boolean-valued expression that appears alongside a set of binders
27+--
24type Guard = Value
28type Guard = Value
25
29
30+-- |
31+-- Built-in unary operators
32+--
26data UnaryOperator
33data UnaryOperator
34+ -- |
35+ -- Numeric negation
36+ --
27 = Negate
37 = Negate
38+ -- |
39+ -- Boolean negation
40+ --
28 | Not
41 | Not
42+ -- |
43+ -- Bitwise negation
44+ --
29 | BitwiseNot
45 | BitwiseNot
46+ -- |
47+ -- Numeric unary \'plus\'
48+ --
30 | Positive deriving (Show, Eq, Data, Typeable)
49 | Positive deriving (Show, Eq, Data, Typeable)
31
50
51+-- |
52+-- Built-in binary operators
53+--
32data BinaryOperator
54data BinaryOperator
55+ -- |
56+ -- Numeric addition
57+ --
33 = Add
58 = Add
59+ -- |
60+ -- Numeric subtraction
61+ --
34 | Subtract
62 | Subtract
63+ -- |
64+ -- Numeric multiplication
65+ --
35 | Multiply
66 | Multiply
67+ -- |
68+ -- Numeric division
69+ --
36 | Divide
70 | Divide
71+ -- |
72+ -- Remainder
73+ --
37 | Modulus
74 | Modulus
75+ -- |
76+ -- Generic equality test
77+ --
38 | EqualTo
78 | EqualTo
79+ -- |
80+ -- Generic inequality test
81+ --
39 | NotEqualTo
82 | NotEqualTo
83+ -- |
84+ -- Numeric less-than
85+ --
40 | LessThan
86 | LessThan
87+ -- |
88+ -- Numeric less-than-or-equal
89+ --
41 | LessThanOrEqualTo
90 | LessThanOrEqualTo
91+ -- |
92+ -- Numeric greater-than
93+ --
42 | GreaterThan
94 | GreaterThan
95+ -- |
96+ -- Numeric greater-than-or-equal
97+ --
43 | GreaterThanOrEqualTo
98 | GreaterThanOrEqualTo
99+ -- |
100+ -- Boolean and
101+ --
44 | And
102 | And
103+ -- |
104+ -- Boolean or
105+ --
45 | Or
106 | Or
107+ -- |
108+ -- Bitwise and
109+ --
46 | BitwiseAnd
110 | BitwiseAnd
111+ -- |
112+ -- Bitwise or
113+ --
47 | BitwiseOr
114 | BitwiseOr
115+ -- |
116+ -- Bitwise xor
117+ --
48 | BitwiseXor
118 | BitwiseXor
119+ -- |
120+ -- Bitwise left shift
121+ --
49 | ShiftLeft
122 | ShiftLeft
123+ -- |
124+ -- Bitwise right shift
125+ --
50 | ShiftRight
126 | ShiftRight
127+ -- |
128+ -- Bitwise right shift with zero-fill
129+ --
51 | ZeroFillShiftRight
130 | ZeroFillShiftRight
131+ -- |
132+ -- String concatenation
133+ --
52 | Concat deriving (Show, Eq, Data, Typeable)
134 | Concat deriving (Show, Eq, Data, Typeable)
53
135
136+-- |
137+-- Data type for values
138+--
54data Value
139data Value
140+ -- |
141+ -- A numeric literal
142+ --
55 = NumericLiteral (Either Integer Double)
143 = NumericLiteral (Either Integer Double)
144+ -- |
145+ -- A string literal
146+ --
56 | StringLiteral String
147 | StringLiteral String
148+ -- |
149+ -- A boolean literal
150+ --
57 | BooleanLiteral Bool
151 | BooleanLiteral Bool
152+ -- |
153+ -- Unary operator application
154+ --
58 | Unary UnaryOperator Value
155 | Unary UnaryOperator Value
156+ -- |
157+ -- Binary operator application
158+ --
59 | Binary BinaryOperator Value Value
159 | Binary BinaryOperator Value Value
160+ -- |
161+ -- Binary operator application. During the rebracketing phase of desugaring, this data constructor
162+ -- will be removed.
163+ --
60 | BinaryNoParens (Qualified Ident) Value Value
164 | BinaryNoParens (Qualified Ident) Value Value
165+ -- |
166+ -- Explicit parentheses. During the rebracketing phase of desugaring, this data constructor
167+ -- will be removed.
168+ --
61 | Parens Value
169 | Parens Value
170+ -- |
171+ -- An array literal
172+ --
62 | ArrayLiteral [Value]
173 | ArrayLiteral [Value]
174+ -- |
175+ -- An array indexing expression
176+ --
63 | Indexer Value Value
177 | Indexer Value Value
178+ -- |
179+ -- An object literal
180+ --
64 | ObjectLiteral [(String, Value)]
181 | ObjectLiteral [(String, Value)]
182+ -- |
183+ -- An record property accessor expression
184+ --
65 | Accessor String Value
185 | Accessor String Value
186+ -- |
187+ -- Partial record update
188+ --
66 | ObjectUpdate Value [(String, Value)]
189 | ObjectUpdate Value [(String, Value)]
190+ -- |
191+ -- Function introduction
192+ --
67 | Abs [Ident] Value
193 | Abs [Ident] Value
194+ -- |
195+ -- Function application
196+ --
68 | App Value [Value]
197 | App Value [Value]
198+ -- |
199+ -- Variable
200+ --
69 | Var (Qualified Ident)
201 | Var (Qualified Ident)
202+ -- |
203+ -- Conditional (if-then-else expression)
204+ --
70 | IfThenElse Value Value Value
205 | IfThenElse Value Value Value
206+ -- |
207+ -- A \"Block\" i.e. a collection of statements which evaluate to a value
208+ --
71 | Block [Statement]
209 | Block [Statement]
210+ -- |
211+ -- A data constructor
212+ --
72 | Constructor (Qualified ProperName)
213 | Constructor (Qualified ProperName)
214+ -- |
215+ -- A case expression. During the case expansion phase of desugaring, top-level binders will get
216+ -- desugared into case expressions, hence the need for guards and multiple binders per branch here.
217+ --
73 | Case [Value] [([Binder], Maybe Guard, Value)]
218 | Case [Value] [([Binder], Maybe Guard, Value)]
219+ -- |
220+ -- A value with a type annotation
221+ --
74 | TypedValue Bool Value Type
222 | TypedValue Bool Value Type
223+ -- |
224+ -- A do-notation block
225+ --
75 | Do [DoNotationElement]
226 | Do [DoNotationElement]
227+ -- |
228+ -- A placeholder for a type class dictionary to be inserted later. At the end of type checking, these
229+ -- placeholders will be replaced with actual expressions representing type classes dictionaries which
230+ -- can be evaluated at runtime. The constructor arguments represent (in order): the type class name and
231+ -- instance type, and the type class dictionaries in scope.
232+ --
76 | TypeClassDictionary (Qualified ProperName, Type) [TypeClassDictionaryInScope] deriving (Show, Data, Typeable)
233 | TypeClassDictionary (Qualified ProperName, Type) [TypeClassDictionaryInScope] deriving (Show, Data, Typeable)
77
234
235+-- |
236+-- The type of a type class dictionary
237+--
78data TypeClassDictionaryType
238data TypeClassDictionaryType
239+ -- |
240+ -- A regular type class dictionary
241+ --
79 = TCDRegular
242 = TCDRegular
243+ -- |
244+ -- A type class dictionary which is an alias for an imported dictionary from another module
245+ --
80 | TCDAlias (Qualified Ident) deriving (Show, Eq, Data, Typeable)
246 | TCDAlias (Qualified Ident) deriving (Show, Eq, Data, Typeable)
81
247
248+-- |
249+-- Data representing a type class dictionary which is in scope
250+--
82data TypeClassDictionaryInScope
251data TypeClassDictionaryInScope
83− = TypeClassDictionaryInScope { tcdName :: Qualified Ident
252+ = TypeClassDictionaryInScope {
253+ -- |
254+ -- The identifier with which the dictionary can be accessed at runtime
255+ --
256+ tcdName :: Qualified Ident
257+ -- |
258+ -- The name of the type class to which this type class instance applies
259+ --
84− , tcdClassName :: Qualified ProperName
260+ , tcdClassName :: Qualified ProperName
261+ -- |
262+ -- The type to which this type class instance applies
263+ --
85− , tcdInstanceType :: Type
264+ , tcdInstanceType :: Type
265+ -- |
266+ -- Type class dependencies which must be satisfied to construct this dictionary
267+ --
86− , tcdDependencies :: Maybe [(Qualified ProperName, Type)]
268+ , tcdDependencies :: Maybe [(Qualified ProperName, Type)]
269+ -- |
270+ -- The type of this dictionary
271+ --
87− , tcdType :: TypeClassDictionaryType
272+ , tcdType :: TypeClassDictionaryType
88− } deriving (Show, Data, Typeable)
273+ } deriving (Show, Data, Typeable)
89
274
275+-- |
276+-- A statement in a do-notation block
277+--
90data DoNotationElement
278data DoNotationElement
279+ -- |
280+ -- A monadic value without a binder
281+ --
91 = DoNotationValue Value
282 = DoNotationValue Value
283+ -- |
284+ -- A monadic value with a binder
285+ --
92 | DoNotationBind Binder Value
286 | DoNotationBind Binder Value
287+ -- |
288+ -- A let statement, i.e. a pure value with a binder
289+ --
93 | DoNotationLet Binder Value deriving (Show, Data, Typeable)
290 | DoNotationLet Binder Value deriving (Show, Data, Typeable)
94
291
292+-- |
293+-- Data type for statements which can appear inside a @Block@ expression
294+--
95data Statement
295data Statement
296+ -- |
297+ -- A variable introduction and initial assignment
298+ --
96 = VariableIntroduction Ident Value
299 = VariableIntroduction Ident Value
300+ -- |
301+ -- A variable reassignment
302+ --
97 | Assignment Ident Value
303 | Assignment Ident Value
304+ -- |
305+ -- A while loop
306+ --
98 | While Value [Statement]
307 | While Value [Statement]
308+ -- |
309+ -- A for loop
310+ --
99 | For Ident Value Value [Statement]
311 | For Ident Value Value [Statement]
312+ -- |
313+ -- An if-then-else statement
314+ --
100 | If IfStatement
315 | If IfStatement
316+ -- |
317+ -- A return statement
318+ --
101 | Return Value deriving (Show, Data, Typeable)
319 | Return Value deriving (Show, Data, Typeable)
102
320
321+-- |
322+-- Data type for if-statements
323+--
324+data IfStatement
325+ -- |
326+ -- An if statement. Arguments are (in order): boolean condition, true branch, optional else branch.
327+ --
103−data IfStatement = IfStatement Value [Statement] (Maybe ElseStatement) deriving (Show, Data, Typeable)
328+ = IfStatement Value [Statement] (Maybe ElseStatement) deriving (Show, Data, Typeable)
104
329
330+-- |
331+-- Data type for the else branch in an if-statement
332+--
105data ElseStatement
333data ElseStatement
334+ -- |
335+ -- An else branch
336+ --
106 = Else [Statement]
337 = Else [Statement]
338+ -- |
339+ -- An else-if branch
340+ --
107 | ElseIf IfStatement deriving (Show, Data, Typeable)
341 | ElseIf IfStatement deriving (Show, Data, Typeable)
108
342
343+-- |
344+-- Data type for binders
345+--
109data Binder
346data Binder
347+ -- |
348+ -- Wildcard binder
349+ --
110 = NullBinder
350 = NullBinder
351+ -- |
352+ -- A binder which matches a boolean literal
353+ --
111 | BooleanBinder Bool
354 | BooleanBinder Bool
355+ -- |
356+ -- A binder which matches a string literal
357+ --
112 | StringBinder String
358 | StringBinder String
359+ -- |
360+ -- A binder which matches a numeric literal
361+ --
113 | NumberBinder (Either Integer Double)
362 | NumberBinder (Either Integer Double)
363+ -- |
364+ -- A binder which binds an identifier
365+ --
114 | VarBinder Ident
366 | VarBinder Ident
367+ -- |
368+ -- A binder which matches a data constructor with no argument
369+ --
115 | NullaryBinder (Qualified ProperName)
370 | NullaryBinder (Qualified ProperName)
371+ -- |
372+ -- A binder which matches a data constructor with one argument
373+ --
116 | UnaryBinder (Qualified ProperName) Binder
374 | UnaryBinder (Qualified ProperName) Binder
375+ -- |
376+ -- A binder which matches a record and binds its properties
377+ --
117 | ObjectBinder [(String, Binder)]
378 | ObjectBinder [(String, Binder)]
379+ -- |
380+ -- A binder which matches an array and binds its elements
381+ --
118 | ArrayBinder [Binder]
382 | ArrayBinder [Binder]
383+ -- |
384+ -- A binder which matches an array and binds its head and tail
385+ --
119 | ConsBinder Binder Binder
386 | ConsBinder Binder Binder
387+ -- |
388+ -- A binder which binds its input to an identifier
389+ --
120 | NamedBinder Ident Binder deriving (Show, Data, Typeable)
390 | NamedBinder Ident Binder deriving (Show, Data, Typeable)