@@ -1,333 +1,499 @@
1+{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind #-}
2+{-# LANGUAGE OverloadedStrings #-}
1−module Parse.Expression (term, expr, def) where
3+module Parse.Expression (term, expression, definition) where
5+import Control.Monad (guard)
3import qualified Data.List as List
6import qualified Data.List as List
4−import Text.Parsec hiding (newline, spaces)
7+import qualified Data.Text as Text
8+import Data.Text (Text)
6−import qualified Parse.Binop as Binop
7import Parse.Helpers
10import Parse.Helpers
8−import qualified Parse.Helpers as Help
9import qualified Parse.Literal as Literal
11import qualified Parse.Literal as Literal
10import qualified Parse.Pattern as Pattern
12import qualified Parse.Pattern as Pattern
11import qualified Parse.Type as Type
13import qualified Parse.Type as Type
13import qualified AST.Expression.Source as Src
15import qualified AST.Expression.Source as Src
14−import qualified AST.Literal as L
15import qualified AST.Pattern as P
16import qualified AST.Pattern as P
16import qualified Reporting.Annotation as A
17import qualified Reporting.Annotation as A
18+import qualified Reporting.Region as R
20−-------- Basic Terms --------
22+-- TERMS
23−varTerm :: IParser Src.RawExpr'
25+term :: Parser Src.RawExpr
25− toVar <$> Help.var
27+ do start <- getPosition
29+ [ do literal <- Literal.literal
31+ return (A.at start end (Src.Literal literal))
35+ , do var <- qualifiedVar
37+ return (A.at start end (Src.var var))
28−toVar :: String -> Src.RawExpr'
32− Src.Literal (L.Boolean True)
34− "False" ->
42+-- LISTS
35− Src.Literal (L.Boolean False)
45+list :: R.Position -> Parser Src.RawExpr
50+ [ do (entry, _, space) <- expression
52+ listHelp start [entry]
55+ return (A.at start end (Src.List []))
41−accessor :: IParser Src.RawExpr'
43− do start <- getMyPosition
44− label <- try (char '.' >> rLabel)
47− let ann value =
59+listHelp :: R.Position -> [Src.RawExpr] -> Parser Src.RawExpr
60+listHelp start entries =
64+ (entry, _, space) <- expression
66+ listHelp start (entry:entries)
48− A.at start end value
69+ return (A.at start end (Src.List (reverse entries)))
53− (ann (Src.Access (ann (Src.var "_")) label))
56−negative :: IParser Src.RawExpr'
74+-- TUPLES
59− do (A.A region _) <- addLocation (char '-')
60− notFollowedBy (char '.' <|> char '-')
63− let zero = A.A region (Src.Literal (L.IntNum 0))
64− let minus = A.A region "-"
66− return $ Src.Binop [(zero, minus)] negativeTerm
77+tuple :: R.Position -> Parser Src.RawExpr
84+ let x = A.at start end (Src.var "x")
85+ let y = A.at start end (Src.var "y")
86+ return $ mkLambda start end "x" $ mkLambda start end "y" $
87+ A.at start end (Src.Binop [(x, A.at start end op)] y)
90+ arity <- chompCommas 2
93+ let args = map (\n -> Text.pack ("v" ++ show n)) [ 1 .. arity ]
94+ return (A.at start end (error "TODO" args))
97+ (entry, _, space) <- expression
99+ tupleHelp start [entry]
71−-------- Complex Terms --------
103+mkLambda :: R.Position -> R.Position -> Text -> Src.RawExpr -> Src.RawExpr
104+mkLambda start end arg body =
105+ A.at start end (Src.Lambda (A.at start end (P.Var arg)) body)
74−listTerm :: IParser Src.RawExpr'
108+chompCommas :: Int -> Parser Int
75−listTerm =
109+chompCommas n =
77− [ do pos <- getPosition
111+ [ comma >> chompCommas (n + 1)
78− let uid = show (sourceLine pos) ++ ":" ++ show (sourceColumn pos)
112+ , return n
79− (rawSrc, tipe) <- Literal.shader
80− return $ Src.GLShader uid (filter (/='\r') rawSrc) tipe
81− , braces (Src.List <$> commaSep expr)
85−parensTerm :: IParser Src.RawExpr
116+tupleHelp :: R.Position -> [Src.RawExpr] -> Parser Src.RawExpr
86−parensTerm =
117+tupleHelp start entries =
88− mkFunc args realBody start end =
90− (\arg body -> A.at start end (Src.Lambda (A.at start end (P.Var arg)) body))
91− (A.at start end (realBody (A.at start end . Src.var)))
95− mkFunc ["x","y"] $ \var -> Src.Binop [(var "x", op)] (var "y")
98− do commas <- many1 comma
119+ [ do comma
99− let args = map (('v':) . show) [ 0 .. length commas ]
120+ spaces
100− return $ mkFunc args (\var -> Src.tuple (map var args))
121+ (entry, _, space) <- expression
101−
122+ checkSpaces space
102− parenedExpr =
123+ tupleHelp start (entry:entries)
103− do expressions <- padded (commaSep expr)
124+ , do rightParen
104− return $ \start end ->
125+ end <- getPosition
105− case expressions of
126+ case entries of
106− [expression] ->
127+ [entry] ->
107− expression
128+ return entry
109− A.at start end (Src.tuple expressions)
131+ return (A.at start end (Src.tuple (reverse entries)))
112− start <- getMyPosition
115− [ mkBinop <$> try (addLocation Binop.infixOp)
119− end <- getMyPosition
121− return (mkExpr start end)
124−recordTerm :: IParser Src.RawExpr
126− addLocation $ brackets $ choice $
127− [ do starter <- try (addLocation rLabel)
133− , return (Src.Record [])
136− update (A.A ann starter) =
139− fields <- commaSep1 field
140− return (Src.Update (A.A ann (Src.var starter)) fields)
150− fields <- commaSep field
151− return (Src.Record ((key, value) : fields))
152− , return (Src.Record [(key, value)])
156− do key <- addLocation rLabel
162−term :: IParser Src.RawExpr
136+-- RECORDS
139+record :: R.Position -> Parser Src.RawExpr
146+ return (A.at start end (Src.Record []))
165− [ addLocation $ choice $
147+ , do starter <- addLocation lowVar
166− [ Src.Literal <$> Literal.literal
148+ spaces
167− , listTerm
149+ oneOf
168− , accessor
150+ [ do pipe
169− , negative
151+ spaces
170− ]
152+ firstField <- chompField
171− , accessible $ choice $
153+ fields <- chompFields [firstField]
172− [ addLocation varTerm
154+ end <- getPosition
173− , parensTerm
155+ return (A.at start end (Src.Update (A.map Src.var starter) fields))
174− , recordTerm
156+ , do equals
158+ (value, _, nextSpace) <- expression
159+ checkSpaces nextSpace
160+ fields <- chompFields [(starter, value)]
162+ return (A.at start end (Src.Record fields))
167+type Field = ( A.Located Text, Src.RawExpr )
170+chompFields :: [Field] -> Parser [Field]
176+ chompFields (f : fields)
182+chompField :: Parser Field
184+ do key <- addLocation lowVar
188+ (value, _, endSpace) <- expression
189+ checkSpaces endSpace
181−-------- Applications --------
184−appExpr :: IParser Src.RawExpr
186− expecting "an expression" $
188− ts <- constrainedSpacePrefix term $ \hasSpace ->
189− if hasSpace then return () else notFollowedBy (char '-')
193− _ -> List.foldl' (\f x -> A.merge f x $ Src.App f x) t ts
201+expression :: ExprParser
203+ do start <- getPosition
209+ , do starter <- term
212+ exprHelp start (State [] starter end space)
197−-------- Normal Expressions --------
216+data State =
218+ { _ops :: ![(Src.RawExpr, A.Located Text)]
219+ , _last :: !Src.RawExpr
220+ , _end :: !R.Position
225+exprHelp :: R.Position -> State -> ExprParser
226+exprHelp start (State ops lastExpr end space) =
229+ do checkSpaces space
230+ op <- addLocation infixOp
231+ opSpace <- whitespace
234+ do guard (space /= None && opSpace == None && A.drop op == "-")
236+ newEnd <- getPosition
237+ newSpace <- whitespace
239+ let ann x = A.merge op rawTerm x
240+ let negatedTerm = ann (Src.Binop [(ann Src.zero, op)] rawTerm)
241+ let newLast = A.merge lastExpr rawTerm (Src.App lastExpr negatedTerm)
243+ exprHelp start (State ops newLast newEnd newSpace)
246+ do guard (space /= None && opSpace == None && A.drop op == ".")
248+ newEnd <- getPosition
249+ newSpace <- whitespace
251+ let (A.A (R.Region opStart _) _) = op
252+ let ann x = A.at opStart newEnd x
253+ let body = ann (Src.Access (ann (Src.var "r")) field)
254+ let accessor = mkLambda opStart newEnd "r" body
255+ let newLast = A.merge lastExpr accessor (Src.App lastExpr accessor)
257+ exprHelp start (State ops newLast newEnd newSpace)
260+ do guard (space == None && opSpace == None && A.drop op == ".")
262+ newEnd <- getPosition
263+ newSpace <- whitespace
264+ let (A.A (R.Region lastStart _) _) = lastExpr
265+ let newLast = A.at lastStart newEnd (Src.Access lastExpr field)
266+ exprHelp start (State ops newLast newEnd newSpace)
269+ do checkSpaces opSpace
271+ newEnd <- getPosition
272+ newSpace <- whitespace
273+ let newOps = (lastExpr, op) : ops
274+ exprHelp start (State newOps newLast newEnd newSpace)
277+ do checkSpaces opSpace
278+ newStart <- getPosition
279+ (newLast, newEnd, newSpace) <-
286+ let newOps = (lastExpr, op) : ops
287+ let finalExpr = A.at start newEnd (Src.Binop (reverse newOps) newLast)
288+ return ( finalExpr, newEnd, newSpace )
292+ do checkSpaces space
294+ newEnd <- getPosition
295+ newSpace <- whitespace
296+ let newLast = A.merge lastExpr arg (Src.App lastExpr arg)
297+ exprHelp start (State ops newLast newEnd newSpace)
302+ return ( lastExpr, end, space )
307+ A.at start end (Src.Binop (reverse ops) lastExpr)
309+ return ( finalExpr, end, space )
200−expr :: IParser Src.RawExpr
202− addLocation (choice [ letExpr, caseExpr, ifExpr ])
208−binaryExpr :: IParser Src.RawExpr
314+-- IF EXPRESSION
210− Binop.binops appExpr lastExpr
213− addLocation (choice [ letExpr, caseExpr, ifExpr ])
218−ifExpr :: IParser Src.RawExpr'
317+if_ :: R.Position -> ExprParser
219−ifExpr =
318+if_ start =
220− ifHelp []
319+ ifHelp start []
223−ifHelp :: [(Src.RawExpr, Src.RawExpr)] -> IParser Src.RawExpr'
322+ifHelp :: R.Position -> [(Src.RawExpr, Src.RawExpr)] -> ExprParser
224−ifHelp branches =
323+ifHelp start branches =
225− do try (reserved "if")
324+ do keyword "if"
226− whitespace
325+ spaces
227− condition <- expr
326+ (condition, _, condSpace) <- expression
228− padded (reserved "then")
327+ checkSpaces condSpace
229− thenBranch <- expr
330+ (thenBranch, _, thenSpace) <- expression
230− whitespace <?> "an 'else' branch"
331+ checkSpaces thenSpace
231− reserved "else" <?> "an 'else' branch"
332+ keyword "else"
232− whitespace
333+ spaces
233 let newBranches = (condition, thenBranch) : branches
334 let newBranches = (condition, thenBranch) : branches
235− [ ifHelp newBranches
336+ [ ifHelp start newBranches
337+ , do (elseBranch, elseEnd, elseSpace) <- expression
236− , Src.If (reverse newBranches) <$> expr
338+ let ifExpr = A.at start elseEnd (Src.If (reverse newBranches) elseBranch)
339+ return ( ifExpr, elseEnd, elseSpace )
240−lambdaExpr :: IParser Src.RawExpr
343+
241−lambdaExpr =
344+-- LAMBDA EXPRESSION
242− do start <- getMyPosition
345+
243− char '\\' <|> char '\x03BB' <?> "an anonymous function"
346+
244− whitespace
347+function :: R.Position -> ExprParser
245− args <- spaceSep1 Pattern.term
351+ arg <- Pattern.term
246− padded rightArrow
352+ spaces
247− body <- expr
353+ revArgs <- gatherArgs [arg]
248− end <- getMyPosition
354+ spaces
355+ (body, end, space) <- expression
249− return (foldr (\a b -> A.at start end $ Src.Lambda a b) body args)
356+ let func = List.foldl' (\e x -> A.at start end (Src.Lambda x e)) body revArgs
250−
357+ return ( func, end, space )
252−caseExpr :: IParser Src.RawExpr'
359+
253−caseExpr =
360+gatherArgs :: [P.Raw] -> Parser [P.Raw]
254− do try (reserved "case")
361+gatherArgs args =
255− exp <- padded expr
362+ oneOf
256− reserved "of"
363+ [ do arg <- Pattern.term
257− whitespace
364+ spaces
258− Help.withPos $
365+ gatherArgs (arg:args)
259− do firstBranch <- branch
366+ , do rightArrow
260− branches <-
367+ return args
262− try (whitespace >> Help.checkIndent)
369+
264− return $ Src.Case exp (firstBranch : branches)
371+
265− where
372+-- CASE EXPRESSIONS
267− do p <- Pattern.expr
374+
375+case_ :: R.Position -> ExprParser
379+ (switcher, _, switcherSpace) <- expression
380+ checkSpaces switcherSpace
383+ oldIndent <- getIndent
386+ (firstBranch, firstEnd, firstSpace) <- branchHelp
387+ (branches, end, space) <- caseHelp [firstBranch] firstEnd firstSpace
390+ ( A.at start end (Src.Case switcher branches)
396+branchHelp :: SParser (P.Raw, Src.RawExpr)
398+ do (pattern, patternSpace) <- Pattern.expression
399+ checkSpaces patternSpace
268− padded rightArrow
400+ rightArrow
269− (,) p <$> expr
401+ spaces
270−
402+ (branchExpr, end, space) <- expression
271−
403+ return ( (pattern, branchExpr), end, space )
274−
406+caseHelp :: [(P.Raw, Src.RawExpr)] -> R.Position -> Space -> SParser [(P.Raw, Src.RawExpr)]
275−
407+caseHelp branches end space =
276−letExpr :: IParser Src.RawExpr'
408+ case space of
277−letExpr =
409+ Aligned ->
278− do try (reserved "let")
410+ do (branch, newEnd, newSpace) <- branchHelp
279− whitespace
411+ caseHelp (branch:branches) newEnd newSpace
280− defs <- Help.block (def <* whitespace)
412+
282− reserved "in"
414+ return ( reverse branches, end, space )
421+let_ :: R.Position -> ExprParser
423+ do oldIndent <- getIndent
430+ (def, end, space) <- definition
431+ letHelp start oldIndent [def] end space
434+letHelp :: R.Position -> Int -> [Src.RawDef] -> R.Position -> Space -> ExprParser
435+letHelp start oldIndent defs end space =
438+ do (def, newEnd, newSpace) <- definition
439+ letHelp start oldIndent (def:defs) newEnd newSpace
442+ failure (error "TODO missing `in`")
448+ (body, newEnd, newSpace) <- expression
284− Src.Let defs <$> expr
449+ let letExpr = A.at start end (Src.Let defs body)
285−
450+ return ( letExpr, newEnd, newSpace )
287−def :: IParser Src.RawDef
457+definition :: SParser Src.RawDef
288−def =
458+definition =
289− addLocation $ Help.withPos $
290− do start <- defStart
459+ do start <- getPosition
291− whitespace
460+ root <- rootPattern start
292− case start of
461+ spaces
293− A.A _ (P.Var name) ->
463+ P.Var name ->
295− [ do hasType
465+ [ do hasType
296− whitespace
466+ spaces
297− tipe <- Type.expr
467+ (tipe, end, space) <- Type.expression
298− return $ Src.Annotation name tipe
468+ return ( A.at start end (Src.Annotation name tipe), end, space )
299− , defEnd start []
469+ , definitionHelp start root []
303− defEnd start []
473+ definitionHelp start root []
306−defStart :: IParser P.Raw
476+rootPattern :: R.Position -> Parser P.Raw
307−defStart =
477+rootPattern start =
309− [ addLocation $ try $
479+ [ do op <- try (leftParen >> infixOp)
310− do char '('
480+ rightParen
311− op <- Binop.infixOp
481+ end <- getPosition
313− return (P.Var op)
482+ return (A.at start end (P.Var op))
314 , Pattern.term
483 , Pattern.term
318−defEnd :: P.Raw -> [P.Raw] -> IParser Src.RawDef'
487+definitionHelp :: R.Position -> P.Raw -> [P.Raw] -> SParser Src.RawDef
319−defEnd start revArgs =
488+definitionHelp start root revArgs =
321 [ do arg <- Pattern.term
490 [ do arg <- Pattern.term
322− whitespace
491+ spaces
323− defEnd start (arg : revArgs)
492+ definitionHelp start root (arg : revArgs)
324 , do equals
493 , do equals
325− whitespace
494+ spaces
326− body <- expr
495+ (expr, end, space) <- expression
327− return $ Src.Definition start (makeFunction revArgs body)
496+ let body = List.foldl' (\e x -> A.at start end (Src.Lambda x e)) expr revArgs
497+ let def = A.at start end (Src.Definition root body)
498+ return ( def, end, space )
331−makeFunction :: [P.Raw] -> Src.RawExpr -> Src.RawExpr
332−makeFunction revArgs body@(A.A ann _) =
333− List.foldl' (\expr arg -> A.A ann $ Src.Lambda arg expr) body revArgs