1module Parse.Expression {-(def,term)-} where
3import Control.Applicative ((<$>), (<*>))
4import Data.List (foldl')
5import Text.Parsec hiding (newline,spaces)
6import Text.Parsec.Indent
7import qualified Text.Pandoc as Pan
10import qualified Parse.Pattern as Pattern
11import qualified Parse.Type as Type
15import SourceSyntax.Location as Location
16import SourceSyntax.Pattern hiding (tuple,list)
17import qualified SourceSyntax.Literal as Literal
18import SourceSyntax.Expression
19import SourceSyntax.Declaration (Declaration(Definition))
24-------- Basic Terms --------
26varTerm :: IParser (Expr t v)
27varTerm = toVar <$> var <?> "variable"
29toVar :: String -> Expr t v
30toVar v = case v of "True" -> Literal (Literal.Boolean True)
31 "False" -> Literal (Literal.Boolean False)
34accessor :: IParser (Expr t v)
37 lbl <- try (string "." >> rLabel)
39 let loc e = Location.add ("." ++ lbl) (Location.at start end e)
40 return (Lambda (PVar "_") (loc $ Access (loc $ Var "_") lbl))
42negative :: IParser (Expr t v)
45 nTerm <- try (char '-' >> notFollowedBy (char '.' <|> char '-')) >> term
47 let loc e = Location.at start end e
48 return (Binop "-" (loc $ Literal (Literal.IntNum 0)) nTerm)
51-------- Complex Terms --------
53listTerm :: IParser (Expr t v)
55 (do { try $ string "[markdown|"
56 ; md <- filter (/='\r') <$> manyTill anyChar (try $ string "|]")
57 ; return . Markdown $ Pan.readMarkdown Pan.def md })
59 [ try $ do { lo <- expr; whitespace; string ".." ; whitespace
61 , ExplicitList <$> commaSep expr
64parensTerm :: IParser (LExpr t v)
65parensTerm = try (parens opFn) <|> parens (tupleFn <|> parened)
71 let loc = Location.at start end
72 return . loc . Lambda (PVar "x") . loc . Lambda (PVar "y") . loc $
73 Binop op (loc $ Var "x") (loc $ Var "y")
77 let comma = char ',' <?> "comma ','"
78 commas <- comma >> many (whitespace >> comma)
80 let vars = map (('v':) . show) [ 0 .. length commas + 1 ]
81 loc = Location.at start end
82 return $ foldr (\x e -> loc $ Lambda x e)
83 (loc . tuple $ map (loc . Var) vars) (map PVar vars)
89 return $ case es of [e] -> e
90 _ -> Location.at start end (tuple es)
92recordTerm :: IParser (LExpr t v)
93recordTerm = brackets $ choice [ misc, addLocation record ]
96 patterns <- spacePrefix Pattern.term
97 whitespace >> string "=" >> whitespace
99 return (label, makeFunction patterns body)
101 record = Record <$> commaSep field
105 whitespace >> string "<-" >> whitespace
108 remove r = addLocation (string "-" >> whitespace >> Remove r <$> rLabel)
110 insert r = addLocation $ do
111 string "|" >> whitespace
112 Insert r <$> rLabel <*>
113 (whitespace >> string "=" >> whitespace >> expr)
115 modify r = addLocation
116 (string "|" >> whitespace >> Modify r <$> commaSep1 change)
119 record <- addLocation (Var <$> rLabel)
121 opt <- optionMaybe (remove record)
124 Just e -> try (insert e) <|> return e
125 Nothing -> try (insert record) <|> try (modify record)
128term :: IParser (LExpr t v)
129term = addLocation (choice [ Literal <$> literal, listTerm, accessor, negative ])
130 <|> accessible (addLocation varTerm <|> parensTerm <|> recordTerm)
131 <?> "basic term (4, x, 'c', etc.)"
133-------- Applications --------
135appExpr :: IParser (LExpr t v)
138 ts <- constrainedSpacePrefix term $ \str ->
139 if null str then notFollowedBy (char '-') else return ()
142 _ -> foldl' (\f x -> Location.merge f x $ App f x) t ts
144-------- Normal Expressions --------
146binaryExpr :: IParser (LExpr t v)
147binaryExpr = binops [] appExpr lastExpr anyOp
148 where lastExpr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
151ifExpr :: IParser (Expr t v)
152ifExpr = reserved "if" >> whitespace >> (normal <|> multiIf)
156 whitespace ; reserved "then" ; whitespace
158 whitespace <?> "an 'else' branch" ; reserved "else" <?> "an 'else' branch" ; whitespace
160 return $ MultiIf [(bool, thenBranch), (Location.none (Var "otherwise"), elseBranch)]
161 multiIf = MultiIf <$> spaceSep1 iff
162 where iff = do string "|" ; whitespace
163 b <- expr ; whitespace ; string "->" ; whitespace
166lambdaExpr :: IParser (LExpr t v)
167lambdaExpr = do char '\\' <|> char '\x03BB' <?> "anonymous function"
169 args <- spaceSep1 Pattern.term
170 whitespace ; arrow ; whitespace
172 return (makeFunction args body)
174defSet :: IParser [Def t v]
175defSet = block (do d <- def ; whitespace ; return d)
177letExpr :: IParser (Expr t v)
179 reserved "let" ; whitespace
181 whitespace ; reserved "in" ; whitespace
184caseExpr :: IParser (Expr t v)
186 reserved "case"; whitespace; e <- expr; whitespace; reserved "of"; whitespace
187 Case e <$> (with <|> without)
188 where case_ = do p <- Pattern.expr; whitespace; arrow; whitespace
190 with = brackets (semiSep1 (case_ <?> "cases { x -> ... }"))
191 without = block (do c <- case_ ; whitespace ; return c)
193expr = addLocation (choice [ ifExpr, letExpr, caseExpr ])
199 choice [ do p1 <- try Pattern.term
200 infics p1 <|> func p1
201 , func =<< (PVar <$> parens symOp)
202 , (:[]) <$> Pattern.expr
203 ] <?> "the definition of a variable (x = ...)"
207 PVar v -> (pattern:) <$> spacePrefix Pattern.term
208 _ -> do try (lookAhead (whitespace >> string "="))
212 o:p <- try (whitespace >> anyOp)
213 p2 <- (whitespace >> Pattern.term)
214 return $ if o == '`' then [ PVar $ takeWhile (/='`') p, p1, p2 ]
215 else [ PVar (o:p), p1, p2 ]
217makeFunction :: [Pattern] -> LExpr t v -> LExpr t v
218makeFunction args body@(L a b _) =
220 foldr (\arg body' -> pos $ Lambda arg body') body args
222assignExpr :: IParser (Def t v)
223assignExpr = withPos $ do
224 (name:args) <- funcDef
225 whitespace >> string "=" >> whitespace
227 return . Def name $ makeFunction args body
229typeAnnotation :: IParser (Def t v)
230typeAnnotation = TypeAnnotation <$> try start <*> Type.expr
232 start = do v <- lowVar <|> parens symOp
233 whitespace ; hasType ; whitespace
236def :: IParser (Def t v)
237def = typeAnnotation <|> assignExpr
239attempt f parser str =
240 case iParse parser "" str of
241 Right result -> f result
242 Left err -> error $ "Parse error at " ++ show err
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