1{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Parse.Expression (term, expression, definition, rootPattern) where
5import Control.Monad (guard)
6import qualified Data.List as List
7import qualified Data.Text as Text
11import qualified Parse.Literal as Literal
12import qualified Parse.Pattern as Pattern
13import qualified Parse.Type as Type
15import qualified AST.Expression.Source as Src
16import qualified AST.Pattern as P
17import qualified Reporting.Annotation as A
18import qualified Reporting.Error.Syntax as E
19import qualified Reporting.Region as R
26term :: Parser Src.RawExpr
29 do start <- getPosition
31 [ variable start >>= accessible start
33 , Literal.shader start
35 , record start >>= accessible start
36 , tuple start >>= accessible start
41literal :: R.Position -> Parser Src.RawExpr
43 do value <- Literal.literal
45 return (A.at start end (Src.Literal value))
48accessor :: R.Position -> Parser Src.RawExpr
53 let ann x = A.at start end x
54 let body = ann (Src.Access (ann (Src.var "r")) field)
55 return (mkLambda start end "r" body)
58variable :: R.Position -> Parser Src.RawExpr
60 do var <- qualifiedVar
62 return (A.at start end (Src.var var))
65accessible :: R.Position -> Src.RawExpr -> Parser Src.RawExpr
66accessible start expr =
71 let newExpr = A.at start end (Src.Access expr field)
72 accessible start newExpr
81list :: R.Position -> Parser Src.RawExpr
84 inContext start E.ExprList $
87 [ do (entry, _, pos) <- expression
89 listHelp start [entry]
92 return (A.at start end (Src.List []))
96listHelp :: R.Position -> [Src.RawExpr] -> Parser Src.RawExpr
97listHelp start entries =
101 (entry, _, pos) <- expression
103 listHelp start (entry:entries)
106 return (A.at start end (Src.List (reverse entries)))
114tuple :: R.Position -> Parser Src.RawExpr
119 inContext start E.ExprTuple $ oneOf $
120 [ do noSpace pos spos
121 try (minus >> rightParen)
123 return $ A.at start end (Src.var "-")
126 (entry, _, spos2) <- expression
128 tupleHelp start [entry]
130 , do noSpace pos spos
134 return $ A.at start end (Src.var op)
136 , do noSpace pos spos
139 return (A.at start end (Src.tuple []))
141 , do noSpace pos spos
143 arity <- chompCommas 2
146 let args = map (\n -> Text.pack ("v" ++ show n)) [ 1 .. arity ]
147 let ann x = A.at start end x
148 let result = ann (Src.tuple (map (ann . Src.var) args))
149 return (foldr (mkLambda start end) result args)
153mkLambda :: R.Position -> R.Position -> Text -> Src.RawExpr -> Src.RawExpr
154mkLambda start end arg body =
155 A.at start end (Src.Lambda (A.at start end (P.Var arg)) body)
158chompCommas :: Int -> Parser Int
161 [ comma >> chompCommas (n + 1)
166tupleHelp :: R.Position -> [Src.RawExpr] -> Parser Src.RawExpr
167tupleHelp start entries =
171 (entry, _, pos) <- expression
173 tupleHelp start (entry:entries)
181 return (A.at start end (Src.tuple (reverse entries)))
189record :: R.Position -> Parser Src.RawExpr
192 inContext start E.ExprRecord $
197 return (A.at start end (Src.Record []))
198 , do starter <- addLocation lowVar
203 firstField <- chompField
204 fields <- chompFields [firstField]
206 return (A.at start end (Src.Update (A.map Src.var starter) fields))
209 (value, _, nextPos) <- expression
211 fields <- chompFields [(starter, value)]
213 return (A.at start end (Src.Record fields))
218type Field = ( A.Located Text, Src.RawExpr )
221chompFields :: [Field] -> Parser [Field]
227 chompFields (f : fields)
229 return (reverse fields)
233chompField :: Parser Field
235 do key <- addLocation lowVar
239 (value, _, pos) <- expression
252expression :: ExprParser
255 do start <- getPosition
261 , do starter <- possiblyNegativeTerm start
264 exprHelp start (State [] starter end space)
270 { _ops :: ![(Src.RawExpr, A.Located Text)]
271 , _last :: !Src.RawExpr
272 , _end :: !R.Position
277exprHelp :: R.Position -> State -> ExprParser
278exprHelp start (State ops lastExpr end pos) =
284 newEnd <- getPosition
286 let newLast = A.merge lastExpr arg (Src.App lastExpr arg)
287 exprHelp start (State ops newLast newEnd newPos)
291 opStart <- getPosition
294 let op = A.at opStart opEnd opName
296 hint (E.AfterOpExpr opName) (checkSpace spos)
297 newStart <- getPosition
298 hint (E.AfterOpExpr opName) $ oneOf $
300 do guard ("-" == opName && end /= opStart && opEnd == newStart)
302 newEnd <- getPosition
305 let ann x = A.merge op rawTerm x
306 let negatedTerm = ann (Src.Binop [(ann Src.zero, op)] rawTerm)
307 let newLast = A.merge lastExpr rawTerm (Src.App lastExpr negatedTerm)
309 exprHelp start (State ops newLast newEnd newPos)
312 do newLast <- possiblyNegativeTerm newStart
313 newEnd <- getPosition
315 let newOps = (lastExpr, op) : ops
316 exprHelp start (State newOps newLast newEnd newPos)
319 do (newLast, newEnd, newPos) <-
326 let newOps = (lastExpr, op) : ops
327 let finalExpr = A.at start newEnd (Src.Binop (reverse newOps) newLast)
328 return ( finalExpr, newEnd, newPos )
334 return ( lastExpr, end, pos )
339 A.at start end (Src.Binop (reverse ops) lastExpr)
341 return ( finalExpr, end, pos )
345possiblyNegativeTerm :: R.Position -> Parser Src.RawExpr
346possiblyNegativeTerm start =
351 let ann x = A.at start end x
352 return (ann (Src.Binop [(ann Src.zero, ann "-")] expr))
361if_ :: R.Position -> ExprParser
364 inContext start E.ExprIf $ ifHelp start []
367ifHelp :: R.Position -> [(Src.RawExpr, Src.RawExpr)] -> ExprParser
368ifHelp start branches =
370 (condition, _, condPos) <- expression
374 (thenBranch, _, thenPos) <- expression
375 hint E.ElseBranch $ checkSpace thenPos
376 hint E.ElseBranch $ keyword "else"
378 let newBranches = (condition, thenBranch) : branches
381 ifHelp start newBranches
382 , do (elseBranch, elseEnd, elseSpace) <- expression
383 let ifExpr = A.at start elseEnd (Src.If (reverse newBranches) elseBranch)
384 return ( ifExpr, elseEnd, elseSpace )
392function :: R.Position -> ExprParser
395 inContext start E.ExprFunc $
399 revArgs <- gatherArgs [arg]
401 (body, end, space) <- expression
402 let func = List.foldl' (\e x -> A.at start end (Src.Lambda x e)) body revArgs
403 return ( func, end, space )
406gatherArgs :: [P.Raw] -> Parser [P.Raw]
409 [ do arg <- Pattern.term
411 gatherArgs (arg:args)
421case_ :: R.Position -> ExprParser
424 inContext start E.ExprCase $
426 (switcher, _, switcherPos) <- expression
427 checkSpace switcherPos
430 oldIndent <- getIndent
433 (firstBranch, firstEnd, firstPos) <- branchHelp
434 (branches, end, pos) <- caseHelp [firstBranch] firstEnd firstPos
437 ( A.at start end (Src.Case switcher branches)
443branchHelp :: SParser (P.Raw, Src.RawExpr)
445 do (pattern, patternPos) <- Pattern.expression
446 checkSpace patternPos
449 (branchExpr, end, pos) <- expression
450 return ( (pattern, branchExpr), end, pos )
453caseHelp :: [(P.Raw, Src.RawExpr)] -> R.Position -> SPos -> SParser [(P.Raw, Src.RawExpr)]
454caseHelp branches end pos =
456 [ do checkAligned pos
457 (branch, newEnd, newPos) <- branchHelp
458 caseHelp (branch:branches) newEnd newPos
459 , return ( reverse branches, end, pos )
467let_ :: R.Position -> ExprParser
469 do oldIndent <- getIndent
472 pushContext start E.ExprLet
477 (def, end, space) <- definition
478 letHelp start oldIndent [def] end space
481letHelp :: R.Position -> Int -> [Src.RawDef] -> R.Position -> SPos -> ExprParser
482letHelp start oldIndent revDefs end pos =
484 [ do checkAligned pos
485 (def, newEnd, newPos) <- definition
486 letHelp start oldIndent (def:revDefs) newEnd newPos
488 , do setIndent oldIndent
493 (body, newEnd, newPos) <- expression
494 let letExpr = A.at start end (Src.Let (reverse revDefs) body)
495 return ( letExpr, newEnd, newPos )
503definition :: SParser Src.RawDef
505 do start <- getPosition
506 root <- rootPattern start
512 inContext start (E.Annotation name) $
514 (tipe, end, space) <- Type.expression
515 return ( A.at start end (Src.Annotation name tipe), end, space )
516 , inContext start (E.Definition name) $
517 definitionHelp start root []
521 definitionHelp start root []
524rootPattern :: R.Position -> Parser P.Raw
527 [ do op <- try (leftParen >> infixOp)
530 return (A.at start end (P.Var op))
535definitionHelp :: R.Position -> P.Raw -> [P.Raw] -> SParser Src.RawDef
536definitionHelp start root revArgs =
538 [ do arg <- hint E.Arg Pattern.term
540 definitionHelp start root (arg : revArgs)
543 (expr, end, space) <- expression
544 let body = List.foldl' (\e x -> A.at start end (Src.Lambda x e)) expr revArgs
545 let def = A.at start end (Src.Definition root body)
546 return ( def, end, space )
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list