1-----------------------------------------------------------------------------
3-- Module : PureScript.Parser.Values
4-- Copyright : (c) Phil Freeman 2013
7-- Maintainer : Phil Freeman <paf31@cantab.net>
8-- Stability : experimental
13-----------------------------------------------------------------------------
15module PureScript.Parser.Values (
20import PureScript.Values
21import PureScript.Names
22import PureScript.Declarations
23import PureScript.Parser.State
24import Data.Function (on)
26import Data.Functor.Identity
27import qualified Data.Map as M
28import qualified PureScript.Parser.Common as C
29import Control.Applicative
30import qualified Text.Parsec as P
31import Text.Parsec.Expr
33import Control.Arrow (Arrow(..))
34import PureScript.Parser.Types
35import PureScript.Types
37booleanLiteral :: P.Parsec String ParseState Bool
38booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)
40parseNumericLiteral :: P.Parsec String ParseState Value
41parseNumericLiteral = NumericLiteral <$> C.integerOrFloat
43parseStringLiteral :: P.Parsec String ParseState Value
44parseStringLiteral = StringLiteral <$> C.stringLiteral
46parseBooleanLiteral :: P.Parsec String ParseState Value
47parseBooleanLiteral = BooleanLiteral <$> booleanLiteral
49parseArrayLiteral :: P.Parsec String ParseState Value
50parseArrayLiteral = ArrayLiteral <$> C.squares (parseValue `P.sepBy` (C.indented *> C.comma))
52parseObjectLiteral :: P.Parsec String ParseState Value
53parseObjectLiteral = ObjectLiteral <$> C.braces (parseIdentifierAndValue `P.sepBy` (C.indented *> C.comma))
55parseIdentifierAndValue :: P.Parsec String ParseState (String, Value)
56parseIdentifierAndValue = (,) <$> (C.indented *> C.identifier <* C.indented <* C.colon)
57 <*> (C.indented *> parseValue)
59parseAbs :: P.Parsec String ParseState Value
61 C.lexeme $ P.char '\\'
62 args <- (C.indented *> C.parseIdent) `P.sepBy` (C.indented *> C.comma)
63 C.lexeme $ C.indented *> P.string "->"
65 return $ Abs args value
67parseApp :: P.Parsec String ParseState Value
68parseApp = App <$> parseValue
69 <*> (C.indented *> C.parens (parseValue `P.sepBy` (C.indented *> C.comma)))
71parseVar :: P.Parsec String ParseState Value
72parseVar = Var <$> C.parseIdent
74parseConstructor :: P.Parsec String ParseState Value
75parseConstructor = Constructor <$> C.properName
77parseCase :: P.Parsec String ParseState Value
78parseCase = Case <$> P.between (C.reserved "case") (C.indented *> C.reserved "of") parseValue
79 <*> (C.indented *> C.mark (P.many (C.same *> C.mark parseCaseAlternative)))
81parseCaseAlternative :: P.Parsec String ParseState (Binder, Value)
82parseCaseAlternative = (,) <$> (parseGuardedBinder <* C.lexeme (P.string "->"))
84 P.<?> "case alternative"
86parseIfThenElse :: P.Parsec String ParseState Value
87parseIfThenElse = IfThenElse <$> (C.reserved "if" *> C.indented *> parseValue)
88 <*> (C.indented *> C.reserved "then" *> C.indented *> parseValue)
89 <*> (C.indented *> C.reserved "else" *> C.indented *> parseValue)
91parseBlock :: P.Parsec String ParseState Value
92parseBlock = Block <$> (C.reserved "do" *> parseManyStatements)
94parseManyStatements :: P.Parsec String ParseState [Statement]
95parseManyStatements = C.indented *> C.mark (P.many (C.same *> C.mark parseStatement)) P.<?> "block"
97parseValueAtom :: P.Parsec String ParseState Value
98parseValueAtom = C.indented *> P.choice (map P.try
101 , parseBooleanLiteral
110 , C.parens parseValue ])
112parsePropertyUpdate :: P.Parsec String ParseState (String, Value)
113parsePropertyUpdate = do
114 name <- C.lexeme C.identifier
115 C.lexeme $ C.indented *> P.char '='
116 value <- C.indented *> parseValue
119parseValue :: P.Parsec String ParseState Value
121 customOps <- fixities <$> P.getState
122 (buildExpressionParser (operators customOps)
123 . C.buildPostfixParser postfixTable2
124 $ indexersAndAccessors) P.<?> "expression"
126 indexersAndAccessors = C.buildPostfixParser postfixTable1 parseValueAtom
127 postfixTable1 = [ Accessor <$> (C.indented *> C.dot *> C.indented *> C.identifier)
128 , Indexer <$> (C.indented *> C.squares parseValue)
129 , flip ObjectUpdate <$> (C.indented *> C.braces ((C.indented *> parsePropertyUpdate) `P.sepBy1` (C.indented *> C.comma))) ]
130 postfixTable2 = [ C.indented *> indexersAndAccessors >>= \t2 -> return (\t1 -> App t1 [t2])
131 , flip App <$> (C.indented *> C.parens (parseValue `P.sepBy` (C.indented *> C.comma)))
132 , flip TypedValue <$> (P.try (C.lexeme (C.indented *> P.string "::")) *> parsePolyType) ]
134 [ [ Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "!") >> return (Unary Not)
135 , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "~") >> return (Unary BitwiseNot)
136 , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "-") >> return (Unary Negate)
137 , Prefix $ C.lexeme (P.try $ C.indented *> C.reservedOp "+") >> return id ]
138 ] ++ customOperatorTable user ++
139 [ [ Infix (C.lexeme (P.try (C.indented *> C.parseIdentInfix P.<?> "operator") >>= \ident -> return $ \t1 t2 -> App (App (Var ident) [t1]) [t2])) AssocLeft ]
140 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<=") >> return (Binary LessThanOrEqualTo)) AssocRight
141 , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">=") >> return (Binary GreaterThanOrEqualTo)) AssocRight ]
142 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<") >> return (Binary LessThan)) AssocRight
143 , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">") >> return (Binary GreaterThan)) AssocRight ]
144 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "*") >> return (Binary Multiply)) AssocRight
145 , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "/") >> return (Binary Divide)) AssocRight
146 , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "%") >> return (Binary Modulus)) AssocRight ]
147 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "++") >> return (Binary Concat)) AssocRight
148 , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "+") >> return (Binary Add)) AssocRight
149 , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "-") >> return (Binary Subtract)) AssocRight ]
150 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "<<") >> return (Binary ShiftLeft)) AssocRight
151 , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">>>") >> return (Binary ZeroFillShiftRight)) AssocRight
152 , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp ">>") >> return (Binary ShiftRight)) AssocRight ]
153 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "==") >> return (Binary EqualTo)) AssocRight
154 , Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "!=") >> return (Binary NotEqualTo)) AssocRight ]
155 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "&") >> return (Binary BitwiseAnd)) AssocRight ]
156 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "^") >> return (Binary BitwiseXor)) AssocRight ]
157 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "|") >> return (Binary BitwiseOr)) AssocRight ]
158 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "&&") >> return (Binary And)) AssocRight ]
159 , [ Infix (C.lexeme (P.try $ C.indented *> C.reservedOp "||") >> return (Binary Or)) AssocRight ]
162customOperatorTable :: M.Map String Fixity -> OperatorTable String ParseState Identity Value
163customOperatorTable fixities =
165 ops = map (\(name, Fixity a p) -> (name, (a, p))) . M.toList $ fixities
166 sorted = sortBy (compare `on` (snd . snd)) ops
167 levels = groupBy ((==) `on` (snd . snd)) sorted
169 map (map $ \(name, (a, _)) ->
170 flip Infix (toAssoc a) $
171 C.lexeme $ P.try $ do
173 C.reservedOp name P.<?> "operator"
174 return $ \t1 t2 -> App (App (Var (Op name)) [t1]) [t2])
178toAssoc :: Associativity -> Assoc
179toAssoc Infixl = AssocLeft
180toAssoc Infixr = AssocRight
182parseVariableIntroduction :: P.Parsec String ParseState Statement
183parseVariableIntroduction = do
185 name <- C.indented *> C.parseIdent
186 C.lexeme $ C.indented *> P.char '='
188 return $ VariableIntroduction name value
190parseAssignment :: P.Parsec String ParseState Statement
193 C.lexeme $ C.indented *> P.char '='
195 return $ Assignment tgt value
197parseWhile :: P.Parsec String ParseState Statement
198parseWhile = While <$> (C.reserved "while" *> C.indented *> parseValue <* C.indented <* C.colon)
199 <*> parseManyStatements
201parseFor :: P.Parsec String ParseState Statement
202parseFor = For <$> (C.reserved "for" *> C.indented *> C.parseIdent)
203 <*> (C.indented *> C.lexeme (P.string "<-") *> parseValue)
204 <*> (C.indented *> C.reserved "until" *> parseValue <* C.colon)
205 <*> parseManyStatements
207parseForEach :: P.Parsec String ParseState Statement
208parseForEach = ForEach <$> (C.reserved "foreach" *> C.indented *> C.parseIdent)
209 <*> (C.indented *> C.reserved "in" *> parseValue <* C.colon)
210 <*> parseManyStatements
212parseIf :: P.Parsec String ParseState Statement
213parseIf = If <$> parseIfStatement
215parseIfStatement :: P.Parsec String ParseState IfStatement
217 IfStatement <$> (C.reserved "if" *> C.indented *> parseValue <* C.indented <* C.colon)
218 <*> parseManyStatements
219 <*> P.optionMaybe (C.same *> parseElseStatement)
221parseElseStatement :: P.Parsec String ParseState ElseStatement
222parseElseStatement = C.reserved "else" >> (ElseIf <$> (C.indented *> parseIfStatement)
223 <|> Else <$> (C.indented *> C.colon *> parseManyStatements))
225parseReturn :: P.Parsec String ParseState Statement
226parseReturn = Return <$> (C.reserved "return" *> parseValue)
228parseStatement :: P.Parsec String ParseState Statement
229parseStatement = P.choice (map P.try
230 [ parseVariableIntroduction
236 , parseReturn ]) P.<?> "statement"
238parseStringBinder :: P.Parsec String ParseState Binder
239parseStringBinder = StringBinder <$> C.stringLiteral
241parseBooleanBinder :: P.Parsec String ParseState Binder
242parseBooleanBinder = BooleanBinder <$> booleanLiteral
244parseNumberBinder :: P.Parsec String ParseState Binder
245parseNumberBinder = NumberBinder <$> C.integerOrFloat
247parseVarBinder :: P.Parsec String ParseState Binder
248parseVarBinder = VarBinder <$> C.parseIdent
250parseNullaryBinder :: P.Parsec String ParseState Binder
251parseNullaryBinder = NullaryBinder <$> C.lexeme C.properName
253parseUnaryBinder :: P.Parsec String ParseState Binder
254parseUnaryBinder = UnaryBinder <$> C.lexeme C.properName <*> (C.indented *> parseBinder)
256parseObjectBinder :: P.Parsec String ParseState Binder
257parseObjectBinder = ObjectBinder <$> C.braces ((C.indented *> parseIdentifierAndBinder) `P.sepBy` (C.indented *> C.comma))
259parseArrayBinder :: P.Parsec String ParseState Binder
260parseArrayBinder = C.squares $ ArrayBinder <$> ((C.indented *> parseBinder) `P.sepBy` (C.indented *> C.comma))
261 <*> P.optionMaybe (C.indented *> C.colon *> C.indented *> parseBinder)
263parseNamedBinder :: P.Parsec String ParseState Binder
264parseNamedBinder = NamedBinder <$> (C.parseIdent <* C.indented <* C.lexeme (P.char '@'))
265 <*> (C.indented *> parseBinder)
267parseNullBinder :: P.Parsec String ParseState Binder
268parseNullBinder = C.lexeme (P.char '_') *> P.notFollowedBy C.identLetter *> return NullBinder
270parseIdentifierAndBinder :: P.Parsec String ParseState (String, Binder)
271parseIdentifierAndBinder = do
272 name <- C.lexeme C.identifier
273 C.lexeme $ C.indented *> P.char '='
274 binder <- C.indented *> parseBinder
275 return (name, binder)
277parseBinder :: P.Parsec String ParseState Binder
278parseBinder = P.choice (map P.try
289 , C.parens parseBinder ]) P.<?> "binder"
291parseGuardedBinder :: P.Parsec String ParseState Binder
292parseGuardedBinder = flip ($) <$> parseBinder <*> P.option id (GuardedBinder <$> (C.indented *> C.lexeme (P.char '|') *> C.indented *> parseValue))
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