1module Parse.Expression (term, annotation, definition, expr, def) where
3import qualified Data.List as List
4import Text.Parsec hiding (newline, spaces)
5import qualified Text.Parsec.Indent as Indent
7import qualified Parse.Binop as Binop
9import qualified Parse.Helpers as Help
10import qualified Parse.Literal as Literal
11import qualified Parse.Pattern as Pattern
12import qualified Parse.Type as Type
14import qualified AST.Expression.General as E
15import qualified AST.Expression.Source as Source
16import qualified AST.Literal as L
17import qualified AST.Pattern as P
18import qualified AST.Type as T
19import qualified AST.Variable as Var
20import qualified Reporting.Annotation as A
24-------- Basic Terms --------
27varTerm :: IParser Source.Expr'
32toVar :: String -> Source.Expr'
36 E.Literal (L.Boolean True)
39 E.Literal (L.Boolean False)
45accessor :: IParser Source.Expr'
47 do (start, lbl, end) <- located (try (string "." >> rLabel))
55 (ann (E.Access (ann (E.rawVar "_")) lbl))
58negative :: IParser Source.Expr'
60 do (start, nTerm, end) <-
63 notFollowedBy (char '.' <|> char '-')
72 (ann (E.Literal (L.IntNum 0)))
77-------- Complex Terms --------
80listTerm :: IParser Source.Expr'
83 [ do pos <- getPosition
84 let uid = show (sourceLine pos) ++ ":" ++ show (sourceColumn pos)
85 (rawSrc, tipe) <- Help.shader
86 return $ E.GLShader uid (filter (/='\r') rawSrc) tipe
87 , braces (E.ExplicitList <$> commaSep expr)
91parensTerm :: IParser Source.Expr
94 mkFunc args realBody start end =
96 (\arg body -> A.at start end (E.Lambda (A.at start end (P.Var arg)) body))
97 (A.at start end (realBody (A.at start end . E.rawVar)))
101 mkFunc ["x","y"] (\var -> E.Binop (Var.Raw op) (var "x") (var "y"))
104 do commas <- many1 comma
105 let args = map (('v':) . show) [ 0 .. length commas ]
106 return $ mkFunc args (\var -> E.tuple (map var args))
109 do expressions <- padded (commaSep expr)
110 return $ \start end ->
115 A.at start end (E.tuple expressions)
117 do (start, mkExpr, end) <-
119 [ mkBinop <$> try (parens Binop.infixOp)
120 , parens (tupleFn <|> parenedExpr)
122 return (mkExpr start end)
125recordTerm :: IParser Source.Expr
127 addLocation $ brackets $ choice $
128 [ do starter <- try (addLocation rLabel)
134 , return (E.Record [])
137 update (A.A ann starter) =
140 fields <- commaSep1 field
141 return (E.Update (A.A ann (E.rawVar starter)) fields)
143 literal (A.A _ starter) =
151 fields <- commaSep field
152 return (E.Record ((starter, value) : fields))
153 , return (E.Record [(starter, value)])
163term :: IParser Source.Expr
165 addLocation (choice [ E.Literal <$> Literal.literal, listTerm, accessor, negative ])
166 <|> accessible (addLocation varTerm <|> parensTerm <|> recordTerm)
171-------- Applications --------
174appExpr :: IParser Source.Expr
176 expecting "an expression" $
178 ts <- constrainedSpacePrefix term $ \str ->
179 if null str then notFollowedBy (char '-') else return ()
183 _ -> List.foldl' (\f x -> A.merge f x $ E.App f x) t ts
187-------- Normal Expressions --------
190expr :: IParser Source.Expr
192 addLocation (choice [ letExpr, caseExpr, ifExpr ])
198binaryExpr :: IParser Source.Expr
200 Binop.binops appExpr lastExpr
203 addLocation (choice [ letExpr, caseExpr, ifExpr ])
208ifExpr :: IParser Source.Expr'
213ifHelp :: [(Source.Expr, Source.Expr)] -> IParser Source.Expr'
215 do try (reserved "if")
218 padded (reserved "then")
220 whitespace <?> "an 'else' branch"
221 reserved "else" <?> "an 'else' branch"
223 let newBranches = (condition, thenBranch) : branches
226 , E.If (reverse newBranches) <$> expr
230lambdaExpr :: IParser Source.Expr
232 do start <- getMyPosition
233 char '\\' <|> char '\x03BB' <?> "an anonymous function"
235 args <- spaceSep1 Pattern.term
239 return (foldr (\a b -> A.at start end $ E.Lambda a b) body args)
242caseExpr :: IParser Source.Expr'
244 do try (reserved "case")
249 do firstBranch <- branch
252 try (whitespace >> Indent.checkIndent)
254 return $ E.Case exp (firstBranch : branches)
266letExpr :: IParser Source.Expr'
268 do try (reserved "let")
271 Indent.block (def <* whitespace)
278def :: IParser Source.Def
281 [ annotation Source.Annotation
282 , definition Source.Definition
290annotation :: (String -> T.Raw -> a) -> IParser (A.Located a)
294 do v <- lowVar <|> parens Binop.infixOp
298 addLocation (creator <$> try start <*> Type.expr)
305definition :: (P.Raw -> Source.Expr -> a) -> IParser (A.Located a)
309 do (name, args) <- defStart
312 return . creator name $ makeFunction args body
315makeFunction :: [P.Raw] -> Source.Expr -> Source.Expr
316makeFunction args body@(A.A ann _) =
317 foldr (\arg body' -> A.A ann $ E.Lambda arg body') body args
320defStart :: IParser (P.Raw, [P.Raw])
322 expecting "the definition of a value (x = ...)" $
323 do starter <- try Pattern.term <|> addLocation (P.Var <$> parens Binop.infixOp)
324 args <- spacePrefix Pattern.term
325 return (starter, args)
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