1module Parse.Expression (def,term,typeAnnotation,expr) where
3import Control.Applicative ((<$>), (<*>))
4import qualified Data.List as List
5import Text.Parsec hiding (newline, spaces)
6import Text.Parsec.Indent (block, withPos)
8import qualified Parse.Binop as Binop
10import qualified Parse.Helpers as Help
11import qualified Parse.Literal as Literal
12import qualified Parse.Pattern as Pattern
13import qualified Parse.Type as Type
15import qualified AST.Annotation as Annotation
16import qualified AST.Expression.General as E
17import qualified AST.Expression.Source as Source
18import qualified AST.Literal as L
19import qualified AST.Pattern as P
20import qualified AST.Variable as Var
23-------- Basic Terms --------
25varTerm :: IParser Source.Expr'
27 toVar <$> var <?> "variable"
30toVar :: String -> Source.Expr'
33 "True" -> E.Literal (L.Boolean True)
34 "False" -> E.Literal (L.Boolean False)
38accessor :: IParser Source.Expr'
40 do (start, lbl, end) <- located (try (string "." >> rLabel))
41 let loc e = Annotation.at start end e
42 return (E.Lambda (P.Var "_") (loc $ E.Access (loc $ E.rawVar "_") lbl))
45negative :: IParser Source.Expr'
47 do (start, nTerm, end) <-
48 located (try (char '-' >> notFollowedBy (char '.' <|> char '-')) >> term)
49 let loc e = Annotation.at start end e
50 return (E.Binop (Var.Raw "-") (loc $ E.Literal (L.IntNum 0)) nTerm)
53-------- Complex Terms --------
55listTerm :: IParser Source.Expr'
57 shader' <|> braces (try range <|> E.ExplicitList <$> commaSep expr)
66 let uid = show (sourceLine pos) ++ ":" ++ show (sourceColumn pos)
67 (rawSrc, tipe) <- Help.shader
68 return $ E.GLShader uid (filter (/='\r') rawSrc) tipe
71parensTerm :: IParser Source.Expr
73 try (parens opFn) <|> parens (tupleFn <|> parened)
76 (start, op, end) <- located anyOp
77 let loc = Annotation.at start end
78 return . loc . E.Lambda (P.Var "x") . loc . E.Lambda (P.Var "y") . loc $
79 E.Binop (Var.Raw op) (loc (E.rawVar "x")) (loc (E.rawVar "y"))
82 let comma = char ',' <?> "comma ','"
83 (start, commas, end) <- located (comma >> many (whitespace >> comma))
84 let vars = map (('v':) . show) [ 0 .. length commas + 1 ]
85 loc = Annotation.at start end
86 return $ foldr (\x e -> loc $ E.Lambda x e)
87 (loc . E.tuple $ map (loc . E.rawVar) vars) (map P.Var vars)
90 (start, es, end) <- located (commaSep expr)
93 _ -> Annotation.at start end (E.tuple es)
95recordTerm :: IParser Source.Expr
97 brackets $ choice [ misc, addLocation record ]
101 patterns <- spacePrefix Pattern.term
104 return (label, makeFunction patterns body)
107 E.Record <$> commaSep field
115 addLocation (string "-" >> whitespace >> E.Remove r <$> rLabel)
119 do string "|" >> whitespace
120 E.Insert r <$> rLabel <*> (padded equals >> expr)
123 addLocation (string "|" >> whitespace >> E.Modify r <$> commaSep1 change)
127 record <- addLocation (E.rawVar <$> rLabel)
128 opt <- padded (optionMaybe (remove record))
130 Just e -> try (insert e) <|> return e
131 Nothing -> try (insert record) <|> try (modify record)
134term :: IParser Source.Expr
135term = addLocation (choice [ E.Literal <$> Literal.literal, listTerm, accessor, negative ])
136 <|> accessible (addLocation varTerm <|> parensTerm <|> recordTerm)
137 <?> "basic term (4, x, 'c', etc.)"
140-------- Applications --------
142appExpr :: IParser Source.Expr
145 ts <- constrainedSpacePrefix term $ \str ->
146 if null str then notFollowedBy (char '-') else return ()
150 _ -> List.foldl' (\f x -> Annotation.merge f x $ E.App f x) t ts
153-------- Normal Expressions --------
155binaryExpr :: IParser Source.Expr
157 Binop.binops appExpr lastExpr anyOp
159 lastExpr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
163ifExpr :: IParser Source.Expr'
165 do try (reserved "if")
171 padded (reserved "then")
173 whitespace <?> "an 'else' branch"
174 reserved "else" <?> "an 'else' branch"
179 , (Annotation.sameAs elseBranch (E.Literal . L.Boolean $ True), elseBranch)
183 E.MultiIf <$> spaceSep1 iff
186 do string "|" ; whitespace
187 b <- expr ; padded arrow
191lambdaExpr :: IParser Source.Expr
193 do char '\\' <|> char '\x03BB' <?> "anonymous function"
195 args <- spaceSep1 Pattern.term
198 return (makeFunction args body)
201defSet :: IParser [Source.Def]
209letExpr :: IParser Source.Expr'
211 do try (reserved "let")
214 padded (reserved "in")
218caseExpr :: IParser Source.Expr'
220 do try (reserved "case")
224 E.Case e <$> (with <|> without)
232 brackets (semiSep1 (case_ <?> "cases { x -> ... }"))
235 block (do c <- case_ ; whitespace ; return c)
238expr :: IParser Source.Expr
239expr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
245defStart :: IParser [P.RawPattern]
247 choice [ do p1 <- try Pattern.term
248 infics p1 <|> func p1
249 , func =<< (P.Var <$> parens symOp)
250 , (:[]) <$> Pattern.expr
251 ] <?> "the definition of a variable (x = ...)"
255 P.Var _ -> (pattern:) <$> spacePrefix Pattern.term
256 _ -> do try (lookAhead (whitespace >> string "="))
260 o:p <- try (whitespace >> anyOp)
261 p2 <- (whitespace >> Pattern.term)
262 return $ if o == '`' then [ P.Var $ takeWhile (/='`') p, p1, p2 ]
263 else [ P.Var (o:p), p1, p2 ]
265makeFunction :: [P.RawPattern] -> Source.Expr -> Source.Expr
266makeFunction args body@(Annotation.A ann _) =
267 foldr (\arg body' -> Annotation.A ann $ E.Lambda arg body') body args
270definition :: IParser Source.Def
273 do (name:args) <- defStart
276 return . Source.Definition name $ makeFunction args body
279typeAnnotation :: IParser Source.Def
281 Source.TypeAnnotation <$> try start <*> Type.expr
284 do v <- lowVar <|> parens symOp
289def :: IParser Source.Def
291 typeAnnotation <|> definition
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