PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Language/Python/Common/ParserUtils.hs

http://github.com/bjpop/language-python
Haskell | 294 lines | 200 code | 38 blank | 56 comment | 9 complexity | 42a40f58e70d5b9a147c519dac2a7153 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. {-# OPTIONS #-}
  2. -----------------------------------------------------------------------------
  3. -- |
  4. -- Module : Language.Python.Common.ParserUtils
  5. -- Copyright : (c) 2009 Bernie Pope
  6. -- License : BSD-style
  7. -- Maintainer : bjpop@csse.unimelb.edu.au
  8. -- Stability : experimental
  9. -- Portability : ghc
  10. --
  11. -- Various utilities to support the Python parser.
  12. -----------------------------------------------------------------------------
  13. module Language.Python.Common.ParserUtils where
  14. import Data.List (foldl')
  15. import Data.Maybe (isJust)
  16. import Control.Monad.Error.Class (throwError)
  17. import Language.Python.Common.AST as AST
  18. import Language.Python.Common.Token as Token
  19. import Language.Python.Common.ParserMonad hiding (location)
  20. import Language.Python.Common.SrcLocation
  21. makeConditionalExpr :: ExprSpan -> Maybe (ExprSpan, ExprSpan) -> ExprSpan
  22. makeConditionalExpr e Nothing = e
  23. makeConditionalExpr e opt@(Just (cond, false_branch))
  24. = CondExpr e cond false_branch (spanning e opt)
  25. makeBinOp :: ExprSpan -> [(OpSpan, ExprSpan)] -> ExprSpan
  26. makeBinOp e es
  27. = foldl' mkOp e es
  28. where
  29. mkOp e1 (op, e2) = BinaryOp op e1 e2 (spanning e1 e2)
  30. parseError :: Token -> P a
  31. parseError = throwError . UnexpectedToken
  32. data Trailer
  33. = TrailerCall { trailer_call_args :: [ArgumentSpan], trailer_span :: SrcSpan }
  34. | TrailerSubscript { trailer_subs :: [Subscript], trailer_span :: SrcSpan }
  35. | TrailerDot { trailer_dot_ident :: IdentSpan, dot_span :: SrcSpan, trailer_span :: SrcSpan }
  36. instance Span Trailer where
  37. getSpan = trailer_span
  38. data Subscript
  39. = SubscriptExpr { subscription :: ExprSpan, subscript_span :: SrcSpan }
  40. | SubscriptSlice
  41. { subscript_slice_span1 :: Maybe ExprSpan
  42. , subscript_slice_span2 :: Maybe ExprSpan
  43. , subscript_slice_span3 :: Maybe (Maybe ExprSpan)
  44. , subscript_span :: SrcSpan
  45. }
  46. | SubscriptSliceEllipsis { subscript_span :: SrcSpan }
  47. instance Span Subscript where
  48. getSpan = subscript_span
  49. isProperSlice :: Subscript -> Bool
  50. isProperSlice (SubscriptSlice {}) = True
  51. isProperSlice (SubscriptSliceEllipsis {}) = True
  52. isProperSlice other = False
  53. subscriptToSlice :: Subscript -> SliceSpan
  54. subscriptToSlice (SubscriptSlice lower upper stride span)
  55. = SliceProper lower upper stride span
  56. subscriptToSlice (SubscriptExpr e span)
  57. = SliceExpr e span
  58. subscriptToSlice (SubscriptSliceEllipsis span)
  59. = SliceEllipsis span
  60. subscriptToExpr :: Subscript -> ExprSpan
  61. subscriptToExpr (SubscriptExpr { subscription = s }) = s
  62. subscriptToExpr other = error "subscriptToExpr applied to non subscript"
  63. subscriptsToExpr :: [Subscript] -> ExprSpan
  64. subscriptsToExpr subs
  65. | length subs > 1 = Tuple (map subscriptToExpr subs) (getSpan subs)
  66. | length subs == 1 = subscriptToExpr $ head subs
  67. | otherwise = error "subscriptsToExpr: empty subscript list"
  68. addTrailer :: ExprSpan -> [Trailer] -> ExprSpan
  69. addTrailer
  70. = foldl' trail
  71. where
  72. trail :: ExprSpan -> Trailer -> ExprSpan
  73. -- XXX fix the span
  74. trail e trail@(TrailerCall { trailer_call_args = args }) = Call e args (spanning e trail)
  75. trail e trail@(TrailerSubscript { trailer_subs = subs })
  76. | any isProperSlice subs
  77. = SlicedExpr e (map subscriptToSlice subs) (spanning e trail)
  78. | otherwise
  79. = Subscript e (subscriptsToExpr subs) (spanning e trail)
  80. trail e trail@(TrailerDot { trailer_dot_ident = ident, dot_span = ds })
  81. = Dot { dot_expr = e, dot_attribute = ident, expr_annot = spanning e trail }
  82. makeTupleOrExpr :: [ExprSpan] -> Maybe Token -> ExprSpan
  83. makeTupleOrExpr [e] Nothing = e
  84. makeTupleOrExpr es@(_:_) (Just t) = Tuple es (spanning es t)
  85. makeTupleOrExpr es@(_:_) Nothing = Tuple es (getSpan es)
  86. makeAssignmentOrExpr :: ExprSpan -> Either [ExprSpan] (AssignOpSpan, ExprSpan) -> StatementSpan
  87. makeAssignmentOrExpr e (Left es)
  88. = makeNormalAssignment e es
  89. where
  90. makeNormalAssignment :: ExprSpan -> [ExprSpan] -> StatementSpan
  91. makeNormalAssignment e [] = StmtExpr e (getSpan e)
  92. makeNormalAssignment e es
  93. = AST.Assign (e : front) (head back) (spanning e es)
  94. where
  95. (front, back) = splitAt (len - 1) es
  96. len = length es
  97. makeAssignmentOrExpr e1 (Right (op, e2))
  98. = makeAugAssignment e1 op e2
  99. where
  100. makeAugAssignment :: ExprSpan -> AssignOpSpan -> ExprSpan -> StatementSpan
  101. makeAugAssignment e1 op e2
  102. = AST.AugmentedAssign e1 op e2 (spanning e1 e2)
  103. makeTry :: Token -> SuiteSpan -> ([HandlerSpan], [StatementSpan], [StatementSpan]) -> StatementSpan
  104. makeTry t1 body (handlers, elses, finally)
  105. = AST.Try body handlers elses finally
  106. (spanning (spanning (spanning (spanning t1 body) handlers) elses) finally)
  107. makeParam :: (IdentSpan, Maybe ExprSpan) -> Maybe ExprSpan -> ParameterSpan
  108. makeParam (name, annot) defaultVal
  109. = Param name annot defaultVal paramSpan
  110. where
  111. paramSpan = spanning (spanning name annot) defaultVal
  112. makeStarParam :: Token -> Maybe (IdentSpan, Maybe ExprSpan) -> ParameterSpan
  113. makeStarParam t1 Nothing = EndPositional (getSpan t1)
  114. makeStarParam t1 (Just (name, annot))
  115. = VarArgsPos name annot (spanning t1 annot)
  116. makeStarStarParam :: Token -> (IdentSpan, Maybe ExprSpan) -> ParameterSpan
  117. makeStarStarParam t1 (name, annot)
  118. = VarArgsKeyword name annot (spanning (spanning t1 name) annot)
  119. -- version 2 only
  120. makeTupleParam :: ParamTupleSpan -> Maybe ExprSpan -> ParameterSpan
  121. -- just a name
  122. makeTupleParam p@(ParamTupleName {}) optDefault =
  123. Param (param_tuple_name p) Nothing optDefault (spanning p optDefault)
  124. -- a parenthesised tuple. NOTE: we do not distinguish between (foo) and (foo,)
  125. makeTupleParam p@(ParamTuple { param_tuple_annot = span }) optDefault =
  126. UnPackTuple p optDefault span
  127. makeComprehension :: ExprSpan -> CompForSpan -> ComprehensionSpan
  128. makeComprehension e for = Comprehension (ComprehensionExpr e) for (spanning e for)
  129. makeListForm :: SrcSpan -> Either ExprSpan ComprehensionSpan -> ExprSpan
  130. makeListForm span (Left tuple@(Tuple {})) = List (tuple_exprs tuple) span
  131. makeListForm span (Left other) = List [other] span
  132. makeListForm span (Right comprehension) = ListComp comprehension span
  133. makeSet :: ExprSpan -> Either CompForSpan [ExprSpan] -> SrcSpan -> ExprSpan
  134. makeSet e (Left compFor) = SetComp (Comprehension (ComprehensionExpr e) compFor (spanning e compFor))
  135. makeSet e (Right es) = Set (e:es)
  136. makeDictionary :: (ExprSpan, ExprSpan) -> Either CompForSpan [(ExprSpan,ExprSpan)] -> SrcSpan -> ExprSpan
  137. makeDictionary mapping@(key, val) (Left compFor) =
  138. DictComp (Comprehension (ComprehensionDict (DictMappingPair key val)) compFor (spanning mapping compFor))
  139. makeDictionary (key, val) (Right es) =
  140. Dictionary (DictMappingPair key val: map (\(e1, e2) -> DictMappingPair e1 e2) es)
  141. fromEither :: Either a a -> a
  142. fromEither (Left x) = x
  143. fromEither (Right x) = x
  144. makeDecorator :: Token -> DottedNameSpan -> [ArgumentSpan] -> DecoratorSpan
  145. makeDecorator t1 name [] = Decorator name [] (spanning t1 name)
  146. makeDecorator t1 name args = Decorator name args (spanning t1 args)
  147. -- parser guarantees that the first list is non-empty
  148. makeDecorated :: [DecoratorSpan] -> StatementSpan -> StatementSpan
  149. makeDecorated ds@(d:_) def = Decorated ds def (spanning d def)
  150. -- suite can't be empty so it is safe to take span over it
  151. makeFun :: Token -> IdentSpan -> [ParameterSpan] -> Maybe ExprSpan -> SuiteSpan -> StatementSpan
  152. makeFun t1 name params annot body =
  153. Fun name params annot body $ spanning t1 body
  154. makeReturn :: Token -> Maybe ExprSpan -> StatementSpan
  155. makeReturn t1 Nothing = AST.Return Nothing (getSpan t1)
  156. makeReturn t1 expr@(Just e) = AST.Return expr (spanning t1 e)
  157. makeParenOrGenerator :: Either ExprSpan ComprehensionSpan -> SrcSpan -> ExprSpan
  158. makeParenOrGenerator (Left e) span = Paren e span
  159. makeParenOrGenerator (Right comp) span = Generator comp span
  160. makePrint :: Bool -> Maybe ([ExprSpan], Maybe Token) -> SrcSpan -> StatementSpan
  161. makePrint chevron Nothing span = AST.Print chevron [] False span
  162. makePrint chevron (Just (args, last_comma)) span =
  163. AST.Print chevron args (isJust last_comma) span
  164. makeRelative :: [Either Token DottedNameSpan] -> ImportRelativeSpan
  165. makeRelative items =
  166. ImportRelative ndots maybeName (getSpan items)
  167. where
  168. (ndots, maybeName) = countDots 0 items
  169. -- parser ensures that the dotted name will be at the end
  170. -- of the list if it is there at all
  171. countDots :: Int -> [Either Token DottedNameSpan] -> (Int, Maybe DottedNameSpan)
  172. countDots count [] = (count, Nothing)
  173. countDots count (Right name:_) = (count, Just name)
  174. countDots count (Left token:rest) = countDots (count + dots token) rest
  175. dots (DotToken {}) = 1
  176. dots (EllipsisToken {}) = 3
  177. {-
  178. See: http://www.python.org/doc/3.0/reference/expressions.html#calls
  179. arglist: (argument ',')* (argument [',']
  180. |'*' test (',' argument)* [',' '**' test]
  181. |'**' test)
  182. (state 1) Positional arguments come first.
  183. (state 2) Then keyword arguments.
  184. (state 3) Then the single star form.
  185. (state 4) Then more keyword arguments (but no positional arguments).
  186. (state 5) Then the double star form.
  187. XXX fixme: we need to include SrcLocations for the errors.
  188. -}
  189. checkArguments :: [ArgumentSpan] -> P [ArgumentSpan]
  190. checkArguments args = do
  191. check 1 args
  192. return args
  193. where
  194. check :: Int -> [ArgumentSpan] -> P ()
  195. check state [] = return ()
  196. check 5 (arg:_) = spanError arg "an **argument must not be followed by any other arguments"
  197. check state (arg:rest) = do
  198. case arg of
  199. ArgExpr {}
  200. | state == 1 -> check state rest
  201. | state == 2 -> spanError arg "a positional argument must not follow a keyword argument"
  202. | otherwise -> spanError arg "a positional argument must not follow a *argument"
  203. ArgKeyword {}
  204. | state `elem` [1,2] -> check 2 rest
  205. | state `elem` [3,4] -> check 4 rest
  206. ArgVarArgsPos {}
  207. | state `elem` [1,2] -> check 3 rest
  208. | state `elem` [3,4] -> spanError arg "there must not be two *arguments in an argument list"
  209. ArgVarArgsKeyword {} -> check 5 rest
  210. {-
  211. See: http://docs.python.org/3.1/reference/compound_stmts.html#grammar-token-parameter_list
  212. parameter_list ::= (defparameter ",")*
  213. ( "*" [parameter] ("," defparameter)*
  214. [, "**" parameter]
  215. | "**" parameter
  216. | defparameter [","] )
  217. (state 1) Parameters/unpack tuples first.
  218. (state 2) Then the single star (on its own or with parameter)
  219. (state 3) Then more parameters.
  220. (state 4) Then the double star form.
  221. XXX fixme, add support for version 2 unpack tuple.
  222. -}
  223. checkParameters :: [ParameterSpan] -> P [ParameterSpan]
  224. checkParameters params = do
  225. check 1 params
  226. return params
  227. where
  228. check :: Int -> [ParameterSpan] -> P ()
  229. check state [] = return ()
  230. check 4 (param:_) = spanError param "a **parameter must not be followed by any other parameters"
  231. check state (param:rest) = do
  232. case param of
  233. -- Param and UnPackTuple are treated the same.
  234. UnPackTuple {}
  235. | state `elem` [1,3] -> check state rest
  236. | state == 2 -> check 3 rest
  237. Param {}
  238. | state `elem` [1,3] -> check state rest
  239. | state == 2 -> check 3 rest
  240. EndPositional {}
  241. | state == 1 -> check 2 rest
  242. | otherwise -> spanError param "there must not be two *parameters in a parameter list"
  243. VarArgsPos {}
  244. | state == 1 -> check 2 rest
  245. | otherwise -> spanError param "there must not be two *parameters in a parameter list"
  246. VarArgsKeyword {} -> check 4 rest
  247. {-
  248. spanError :: Span a => a -> String -> P ()
  249. spanError x str = throwError $ StrError $ unwords [prettyText $ getSpan x, str]
  250. -}