git.iko.soy/rowtype-yoga/purescript-native
on 667eeef help sign in
222 lines 9.1 kB history raw
1-----------------------------------------------------------------------------
2--
3-- Module : PureScript.Parser.Values
4-- Copyright : (c) Phil Freeman 2013
5-- License : MIT
6--
7-- Maintainer : Phil Freeman <paf31@cantab.net>
8-- Stability : experimental
9-- Portability :
10--
11-- |
12--
13-----------------------------------------------------------------------------
15module PureScript.Parser.Values (
16 parseValue,
17 parseBinder
18) where
20import PureScript.Values
21import qualified PureScript.Parser.Common as C
22import Control.Applicative
23import qualified Text.Parsec as P
24import Text.Parsec.Expr
25import Control.Monad
26import Control.Arrow (Arrow(..))
27import PureScript.Parser.Types
28import PureScript.Types
30booleanLiteral :: P.Parsec String () Bool
31booleanLiteral = (C.reserved "true" >> return True) P.<|> (C.reserved "false" >> return False)
33parseNumericLiteral :: P.Parsec String () Value
34parseNumericLiteral = NumericLiteral <$> C.naturalOrFloat
36parseStringLiteral :: P.Parsec String () Value
37parseStringLiteral = StringLiteral <$> C.stringLiteral
39parseBooleanLiteral :: P.Parsec String () Value
40parseBooleanLiteral = BooleanLiteral <$> booleanLiteral
42parseArrayLiteral :: P.Parsec String () Value
43parseArrayLiteral = ArrayLiteral <$> (C.squares $ C.commaSep parseValue)
45parseObjectLiteral :: P.Parsec String () Value
46parseObjectLiteral = ObjectLiteral <$> (C.braces $ C.commaSep parseIdentifierAndValue)
48parseIdentifierAndValue :: P.Parsec String () (String, Value)
49parseIdentifierAndValue = do
50 name <- C.lexeme C.identifier
51 C.colon
52 value <- parseValue
53 return (name, value)
55parseAbs :: P.Parsec String () Value
56parseAbs = do
57 C.lexeme $ P.char '\\'
58 args <- C.commaSep C.identifier
59 C.lexeme $ P.string "->"
60 value <- parseValue
61 return $ Abs args value
63parseApp :: P.Parsec String () Value
64parseApp = App <$> parseValue
65 <*> (C.parens $ C.commaSep parseValue)
67parseVar :: P.Parsec String () Value
68parseVar = Var <$> (C.identifier <|> C.properName)
70parseCase :: P.Parsec String () Value
71parseCase = Case <$> P.between (C.reserved "case") (C.reserved "of") parseValue
72 <*> C.braces (C.semiSep parseCaseAlternative)
74parseCaseAlternative :: P.Parsec String () (Binder, Value)
75parseCaseAlternative = (,) <$> (parseBinder <* C.lexeme (P.string "->")) <*> parseValue
77parseBlock :: P.Parsec String () Value
78parseBlock = Block <$> (C.braces $ P.many (parseStatement True))
80parseValueAtom :: P.Parsec String () Value
81parseValueAtom = P.choice $ map P.try
82 [ parseNumericLiteral
83 , parseStringLiteral
84 , parseBooleanLiteral
85 , parseArrayLiteral
86 , parseObjectLiteral
87 , parseAbs
88 , parseVar
89 , parseBlock
90 , parseCase
91 , C.parens parseValue ]
93parseValue :: P.Parsec String () Value
94parseValue = buildExpressionParser operators $ C.fold (C.lexeme typedValue) (C.lexeme funArgs) App
95 where
96 typedValue = C.augment parseValueAtom parseTypeAnnotation TypedValue
97 funArgs = C.parens $ C.commaSep parseValue
98 parseTypeAnnotation = C.lexeme (P.string "::") *> parseType
99 operators = [ [ Postfix $ Accessor <$> (C.dot *> C.identifier)
100 , Postfix $ Indexer <$> C.squares parseValue ]
101 , [ Prefix $ C.lexeme (P.char '!') >> return (Unary Not)
102 , Prefix $ C.lexeme (P.char '~') >> return (Unary BitwiseNot)
103 , Prefix $ C.lexeme (P.char '-') >> return (Unary Negate) ]
104 , [ Infix (C.lexeme (P.try (P.string "<=")) >> return (Binary LessThanOrEqualTo)) AssocRight
105 , Infix (C.lexeme (P.try (P.string ">=")) >> return (Binary GreaterThanOrEqualTo)) AssocRight
106 , Infix (C.lexeme (P.try (P.char '<' <* P.notFollowedBy (P.char '<'))) >> return (Binary LessThan)) AssocRight ]
107 , [ Infix (C.lexeme (P.try (P.char '>' <* P.notFollowedBy (P.char '>'))) >> return (Binary GreaterThan)) AssocRight
108 , Infix (C.lexeme (P.char '/') >> return (Binary Divide)) AssocRight
109 , Infix (C.lexeme (P.char '%') >> return (Binary Modulus)) AssocRight ]
110 , [ Infix (C.lexeme (P.try (P.string "++")) >> return (Binary Concat)) AssocRight
111 , Infix (C.lexeme (P.char '+') >> return (Binary Add)) AssocRight
112 , Infix (C.lexeme (P.char '-') >> return (Binary Subtract)) AssocRight ]
113 , [ Infix (C.lexeme (P.string "<<") >> return (Binary ShiftLeft)) AssocRight
114 , Infix (C.lexeme (P.try (P.string ">>>")) >> return (Binary ZeroFillShiftRight)) AssocRight
115 , Infix (C.lexeme (P.string ">>") >> return (Binary ShiftRight)) AssocRight ]
116 , [ Infix (C.lexeme (P.string "==") >> return (Binary EqualTo)) AssocRight
117 , Infix (C.lexeme (P.try (P.string "!=")) >> return (Binary NotEqualTo)) AssocRight ]
118 , [ Infix (C.lexeme (P.try (P.char '&' <* P.notFollowedBy (P.char '&'))) >> return (Binary BitwiseAnd)) AssocRight ]
119 , [ Infix (C.lexeme (P.char '^') >> return (Binary BitwiseXor)) AssocRight ]
120 , [ Infix (C.lexeme (P.try (P.char '|' <* P.notFollowedBy (P.char '|'))) >> return (Binary BitwiseOr)) AssocRight ]
121 , [ Infix (C.lexeme (P.string "&&") >> return (Binary And)) AssocRight ]
122 , [ Infix (C.lexeme (P.string "||") >> return (Binary Or)) AssocRight ]
123 ]
125parseVariableIntroduction :: Bool -> P.Parsec String () Statement
126parseVariableIntroduction requireSemi = do
127 C.reserved "var"
128 name <- C.identifier
129 C.lexeme $ P.char '='
130 value <- parseValue
131 when requireSemi (void C.semi)
132 return $ VariableIntroduction name value
134parseAssignment :: Bool -> P.Parsec String () (Statement)
135parseAssignment requireSemi = do
136 tgt <- parseAssignmentTarget
137 C.lexeme $ P.char '='
138 value <- parseValue
139 when requireSemi (void C.semi)
140 return $ Assignment tgt value
142parseManyStatements :: P.Parsec String () [Statement]
143parseManyStatements = C.braces $ P.many (parseStatement True)
145parseWhile :: P.Parsec String () Statement
146parseWhile = While <$> (C.reserved "while" *> C.parens parseValue)
147 <*> parseManyStatements
149parseFor :: P.Parsec String () Statement
150parseFor = For <$> (C.reserved "for" *> C.parens forIntro)
151 <*> parseManyStatements
152 where
153 forIntro = (,,) <$> parseStatement False
154 <*> (C.semi *> parseValue)
155 <*> (C.semi *> parseStatement False)
157parseIfThenElse :: P.Parsec String () Statement
158parseIfThenElse = IfThenElse
159 <$> (C.reserved "if" *> C.parens parseValue)
160 <*> parseManyStatements
161 <*> P.optionMaybe (C.reserved "else" *> parseManyStatements)
163parseReturn :: Bool -> P.Parsec String () Statement
164parseReturn requireSemi = Return <$> (C.reserved "return" *> parseValue <* when requireSemi (void C.semi))
166parseStatement :: Bool -> P.Parsec String () Statement
167parseStatement requireSemi = P.choice $ map P.try
168 [ parseVariableIntroduction requireSemi
169 , parseAssignment requireSemi
170 , parseWhile
171 , parseFor
172 , parseIfThenElse
173 , parseReturn requireSemi ]
175parseStringBinder :: P.Parsec String () Binder
176parseStringBinder = StringBinder <$> C.stringLiteral
178parseBooleanBinder :: P.Parsec String () Binder
179parseBooleanBinder = BooleanBinder <$> booleanLiteral
181parseNumberBinder :: P.Parsec String () Binder
182parseNumberBinder = NumberBinder <$> C.naturalOrFloat
184parseVarBinder :: P.Parsec String () Binder
185parseVarBinder = VarBinder <$> C.lexeme C.identifier
187parseNullaryBinder :: P.Parsec String () Binder
188parseNullaryBinder = NullaryBinder <$> C.lexeme C.properName
190parseUnaryBinder :: P.Parsec String () Binder
191parseUnaryBinder = UnaryBinder <$> C.lexeme C.properName <*> parseBinder
193parseObjectBinder :: P.Parsec String () Binder
194parseObjectBinder = ObjectBinder <$> C.braces (C.commaSep parseIdentifierAndBinder)
196parseArrayBinder :: P.Parsec String () Binder
197parseArrayBinder = C.squares $ ArrayBinder <$> (C.commaSep parseBinder) <*> P.optionMaybe (C.colon *> parseBinder)
199parseIdentifierAndBinder :: P.Parsec String () (String, Binder)
200parseIdentifierAndBinder = do
201 name <- C.lexeme C.identifier
202 C.lexeme $ P.char '='
203 binder <- parseBinder
204 return (name, binder)
206parseBinder :: P.Parsec String () Binder
207parseBinder = P.choice $ map P.try
208 [ parseStringBinder
209 , parseBooleanBinder
210 , parseNumberBinder
211 , parseVarBinder
212 , parseUnaryBinder
213 , parseNullaryBinder
214 , parseObjectBinder
215 , parseArrayBinder
216 , C.parens parseBinder ]
218parseAssignmentTarget :: P.Parsec String () AssignmentTarget
219parseAssignmentTarget = buildExpressionParser operators (AssignVariable <$> C.identifier)
220 where
221 operators = [ [ Postfix $ AssignArrayIndex <$> C.squares parseValue
222 , Postfix $ AssignObjectProperty <$> (C.dot *> C.identifier) ] ]