Abbie's Haskell compiler
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

405 lines
12 KiB

  1. {
  2. {-# LANGUAGE FlexibleContexts, FlexibleInstances, ViewPatterns #-}
  3. module Frontend.Autogen.Parser where
  4. import qualified Data.Text as T
  5. import Data.Maybe
  6. import Frontend.Parser.Foreign
  7. import Frontend.Lexer.Wrapper
  8. import Frontend.Autogen.Lexer
  9. import Frontend.Lexer.Tokens
  10. import Frontend.Parser.Posn
  11. import Frontend.Syntax
  12. import qualified Prelude
  13. import Prelude hiding (span)
  14. import Debug.Trace
  15. import Control.Monad
  16. }
  17. %name parseExp Exp
  18. %name parseMod Module
  19. %name parseType Type
  20. %tokentype { Token }
  21. %monad { Alex }
  22. %lexer { lexer } { Token TokEof _ _ }
  23. %errorhandlertype explist
  24. %error { parseError }
  25. %token
  26. VAR { Token (TokUnqual VarId _) _ _ }
  27. CON { Token (TokUnqual ConId _) _ _ }
  28. QVAR { Token (TokQual VarId _ _) _ _ }
  29. QCON { Token (TokQual ConId _ _) _ _ }
  30. VARSYM { Token (TokUnqualOp VarId _) _ _ }
  31. CONSYM { Token (TokUnqualOp ConId _) _ _ }
  32. QVARSYM { Token (TokQualOp VarId _ _) _ _ }
  33. QCONSYM { Token (TokQualOp ConId _ _) _ _ }
  34. STRING { Token (TokString _) _ _ }
  35. 'eof' { Token TokEof _ _ }
  36. '(' { Token TokOParen _ _ }
  37. ')' { Token TokCParen _ _ }
  38. '{' { Token TokOBrace _ _ }
  39. '}' { Token TokCBrace _ _ }
  40. START { Token TokLStart _ _ }
  41. END { Token TokLEnd _ _ }
  42. '[' { Token TokOSquare _ _ }
  43. ']' { Token TokCSquare _ _ }
  44. '{-#' { Token TokOPragma _ _ }
  45. '#-}' { Token TokCPragma _ _ }
  46. '\\' { Token TokLambda _ _ }
  47. '->' { Token TokArrow _ _ }
  48. '_' { Token TokUnder _ _ }
  49. '::' { Token TokDoubleColon _ _ }
  50. ';' { Token TokSemi _ _ }
  51. '=' { Token TokEqual _ _ }
  52. ',' { Token TokComma _ _ }
  53. '`' { Token TokTick _ _ }
  54. 'let' { Token TokLet _ _ }
  55. 'in' { Token TokIn _ _ }
  56. 'data' { Token TokData _ _ }
  57. 'case' { Token TokCase _ _ }
  58. 'of' { Token TokOf _ _ }
  59. 'module' { Token TokModule _ _ }
  60. 'where' { Token TokWhere _ _ }
  61. 'import' { Token TokImport _ _ }
  62. 'as' { Token TokAs _ _ }
  63. 'qualified' { Token TokQualified _ _ }
  64. 'foreign' { Token TokForeign _ _ }
  65. 'export' { Token TokExport _ _ }
  66. 'safe' { Token TokSafe _ _ }
  67. 'unsafe' { Token TokUnsafe _ _ }
  68. 'ccall' { Token TokCCall _ _ }
  69. %%
  70. Exp :: { Exp }
  71. : InfixExp '::' Type { span $1 $3 $ Annot $1 $3 }
  72. | InfixExp { $1 }
  73. InfixExp :: { Exp }
  74. : LeftExp {- ... -} { $1 }
  75. | LeftExp qop InfixExp { span $1 $3 $ Infix $1 $2 $3 }
  76. LeftExp :: { Exp }
  77. : '\\' Apat List(Apat) '->' Exp { span $1 $5 (makeLams ($2:$3) $5) }
  78. | 'let' LaidOutList(Decl) 'in' Exp { span $1 $4 $ Let (thd $2) $4 }
  79. | FuncExp { $1 }
  80. FuncExp :: { Exp }
  81. : FuncExp Aexp { span $1 $2 $ App $1 $2 }
  82. | Aexp { $1 }
  83. Aexp :: { Exp }
  84. : qvar { span $1 $1 $ Ref $1 }
  85. | gcon { span $1 $1 $ Con $1 }
  86. | '(' CommaList1(Exp) ')' { span $1 $3 $ makeTuple $2 }
  87. | STRING { span $1 $1 $ Literal (LitString (getString $1)) }
  88. Type :: { Type }
  89. : Btype '->' Type { span $1 $3 $ Tyarr $1 $3 }
  90. | Btype { $1 }
  91. Btype :: { Type }
  92. : Btype Atype { span $1 $2 $ Tyapp $1 $2 }
  93. | Atype { $1 }
  94. Atype :: { Type }
  95. : qvar { span $1 $1 $ Tyvar $1 }
  96. | gtycon { span $1 $1 $ Tycon $1 }
  97. | '[' Type ']' { span $1 $3 $ Tylist $2 }
  98. | '(' CommaList1(Type) ')' { span $1 $3 $ makeTupleType $2 }
  99. Pat :: { Pat }
  100. : Lpat { $1 }
  101. Lpat :: { Pat }
  102. : Apat { $1 }
  103. | gcon Apat List(Apat) { span $1 (endOfListPos $2 $3) (ConPat $1 ($2 : $3)) }
  104. | Lpat qconop Pat { span $1 $3 $ InfixPat $1 $2 $3 }
  105. Apat :: { Pat }
  106. : VAR { span $1 $1 $ Var (getVar $1) }
  107. | gcon { span $1 $1 $ ConPat $1 [] }
  108. | '_' { span $1 $1 $ Wildcard }
  109. | '(' CommaList1(Pat) ')' { span $1 $3 $ makeTuplePattern $2 }
  110. Decl :: { Decl }
  111. : CommaList1(VAR) '::' Type { TySig (getVar `fmap` $1) $3 (startPosn (head $1)) (endPosn $3) }
  112. | VAR Apat List(Apat) Rhs { FunDecl (getVar $1) ($2:$3) $4 (startPosn $1) (endPosn $4) }
  113. | Pat Rhs { PatDecl $1 $2 (startPosn $1) (endPosn $2) }
  114. Rhs :: { Rhs }
  115. : '=' Exp { BareRhs $2 [] (startPosn $1) (endPosn $2) }
  116. | '=' Exp 'where' LaidOutList(Decl) { BareRhs $2 (thd $4) (startPosn $1) (endPosn $4) }
  117. LaidOutList(p)
  118. : START Opt(Semis) LOLContents(p, END) { (startPosn $1, lolEnd $3, lolList $3) }
  119. | '{' Opt(Semis) LOLContents(p, '}') { (startPosn $1, lolEnd $3, lolList $3) }
  120. LOLContents(p, End)
  121. : p Semis LOLContents(p,End) { lolCons $1 $3 }
  122. | p Opt(Semis) End { lolCons $1 (emptyLol $3) }
  123. | Opt(Semis) End { emptyLol $2 }
  124. Module :: { Module }
  125. : 'module' CON ImportExportList 'where' LaidOutList(ModItem)
  126. {% do { (imports,items) <- spanModuleItems (thd $5)
  127. ; pure $ Module { moduleName = toModId (getVar $2)
  128. , moduleExports = fst $3
  129. , moduleImports = imports
  130. , moduleItems = items }
  131. }
  132. }
  133. ImportExportList :: { (Maybe [NamespacedItem ParsedVar], Maybe Posn) }
  134. : {-empty-} { (Nothing, Nothing) }
  135. | '(' CommaList(NSItem) ')' { (Just $2, Just (endPosn $3)) }
  136. NSItem :: { NamespacedItem ParsedVar }
  137. : VAR { IEVar (getVar $1) }
  138. | CON { IECon (getVar $1) }
  139. | 'module' CON { IEModule (getVar $2) }
  140. ModItem :: { Item }
  141. : Decl { ModDecl $1 (startPosn $1) (endPosn $1) }
  142. | Import { ModImport $1 (startPosn $1) (endPosn $1) }
  143. | 'foreign' FfiItem { ModFfi $2 (startPosn $1) (endPosn $2) }
  144. Import :: { ModuleImport ParsedVar }
  145. : 'import' modid ImportExportList
  146. { Import $2 (fst $3) False Nothing (startPosn $1) (fromMaybe (endPosn $2) (snd $3)) }
  147. | 'import' modid ImportExportList 'as' CON
  148. { Import $2 (fst $3) False (Just (getVar $5)) (startPosn $1) (endPosn $5) }
  149. | 'import' 'qualified' modid ImportExportList
  150. { Import $3 (fst $4) True Nothing (startPosn $1) (fromMaybe (endPosn $3) (snd $4)) }
  151. | 'import' 'qualified' modid ImportExportList 'as' CON
  152. { Import $3 (fst $4) True (Just (getVar $6)) (startPosn $1) (endPosn $6) }
  153. FfiItem :: { FfiItem ParsedVar }
  154. : 'import' CallConv Safety Entity VAR '::' Type
  155. -- 1 2 3 4 5 6 7
  156. {% do { ffiDesc <- traverse parseForeignItem $4
  157. ; pure $ FfiImport
  158. { fiVarName = getVar $5
  159. , fiType = $7
  160. , fiCallConv = $2
  161. , fiSafety = $3
  162. , fiItem = ffiDesc
  163. , fiBegin = startPosn $1
  164. , fiEnd = endPosn $7 }
  165. } }
  166. Safety :: { Maybe FfiSafety }
  167. : {-empty-} { Nothing }
  168. | 'safe' { Just Safe }
  169. | 'unsafe' { Just Unsafe }
  170. CallConv :: { FfiCallConv }
  171. : 'ccall' { CC_CCall }
  172. Entity :: { Maybe Token }
  173. : {-empty-} { Nothing }
  174. | STRING { Just $1 }
  175. Opt(p)
  176. : { () }
  177. | p { () }
  178. Semis
  179. : ';' Semis { () }
  180. | ';' { () }
  181. qvarid :: { ParsedVar }
  182. qvarid
  183. : VAR { getVar $1 }
  184. | QVAR { getVar $1 }
  185. qvar :: { ParsedVar }
  186. : qvarid { $1 }
  187. | '(' qvarsym ')' { span $1 $3 $2 }
  188. qconid :: { ParsedVar }
  189. qconid
  190. : CON { getVar $1 }
  191. | QCON { getVar $1 }
  192. qcon :: { ParsedVar }
  193. qcon
  194. : qconid { $1 }
  195. | '(' qconsym ')' { span $1 $3 $2 }
  196. qvarsym :: { ParsedVar }
  197. qvarsym : VARSYM { getVar $1 }
  198. | QVARSYM { getVar $1 }
  199. qconsym :: { ParsedVar }
  200. qconsym : CONSYM { getVar $1 }
  201. | QCONSYM { getVar $1 }
  202. qvarop :: { ParsedVar }
  203. : qvarsym { $1 }
  204. | '`' qvar '`' { span $1 $3 $2 }
  205. qconop :: { ParsedVar }
  206. : qconsym { $1 }
  207. | '`' qcon '`' { span $1 $3 $2 }
  208. qop :: { ParsedVar }
  209. : qvarop { $1 }
  210. | qconop { $1 }
  211. gcon :: { ParsedVar }
  212. : qcon { $1 }
  213. | '(' Commas ')' { BuiltinId { varId = tupleConSymName $2
  214. , varBuiltin = BuiltinTuple $2
  215. , varBegin = startPosn $1
  216. , varEnd = endPosn $3 }
  217. }
  218. | '[' ']' { BuiltinId { varId = T.pack "[]"
  219. , varBuiltin = BuiltinNil
  220. , varBegin = startPosn $1
  221. , varEnd = endPosn $2 }
  222. }
  223. gtycon :: { ParsedVar }
  224. : gcon { $1 }
  225. | '(' '->' ')' { BuiltinId { varId = T.pack "[]"
  226. , varBuiltin = BuiltinArrow
  227. , varBegin = startPosn $1
  228. , varEnd = endPosn $2 }
  229. }
  230. Commas :: { Int }
  231. : {- empty -} { 0 }
  232. | ',' Commas { (let x = $2 in x `seq` 1 + x) }
  233. modid : qconid { toModId $1 }
  234. List(p)
  235. : {-empty-} { [] }
  236. | p List(p) { $1:$2 }
  237. CommaList(p)
  238. : {-empty-} { [] }
  239. | p { [$1] }
  240. | p ',' CommaList(p) { $1:$3 }
  241. CommaList1(p)
  242. : p { [$1] }
  243. | p ',' CommaList(p) { $1:$3 }
  244. Block(p)
  245. : START p END { (startPosn $1, endPosn $3, $2) }
  246. | '{' p '}' { (startPosn $1, endPosn $3, $2) }
  247. {
  248. type Exp = FeExpr ParsedVar
  249. type Pat = FePat ParsedVar
  250. type Decl = FeDecl ParsedVar
  251. type Type = FeType ParsedVar
  252. type Rhs = FeRhs ParsedVar
  253. type Module = FeModule ParsedVar
  254. type Item = ModuleItem ParsedVar
  255. lexer cont = alexMonadScan >>= cont
  256. parseError (token, expected) = do
  257. (here, _, _, _) <- alexGetInput
  258. alexThrow $ \fn -> ParseError { parseErrorMessage = "expecting one of: " ++ unwords expected
  259. , parseErrorInlineDesc = Just ("unexpected " ++ show (tokenClass token))
  260. , parseErrorBegin = startPosn token
  261. , parseErrorEnd = here
  262. , parseErrorFilename = fn }
  263. makeLams xs b = foldr Lam b xs
  264. getVar :: Token -> ParsedVar
  265. getVar tok@(Token (TokQual _ p s) _ _) = QualVar { varId = s, varPrefix = p, varBegin = startPosn tok, varEnd = endPosn tok }
  266. getVar tok@(Token (TokUnqual _ s) _ _) = UnqualVar { varId = s, varBegin = startPosn tok, varEnd = endPosn tok }
  267. getVar tok@(Token (TokQualOp _ p s) _ _) = QualVar { varId = s, varPrefix = p, varBegin = startPosn tok, varEnd = endPosn tok }
  268. getVar tok@(Token (TokUnqualOp _ s) _ _) = UnqualVar { varId = s, varBegin = startPosn tok, varEnd = endPosn tok }
  269. getVar _ = error "getVar non-var"
  270. getString (Token (TokString s) _ _) = s
  271. getString _ = error "getString non-string"
  272. data LOL a = LOL { lolEnd :: Posn, lolList :: [a] }
  273. emptyLol :: HasPosn x => x -> LOL a
  274. emptyLol t = LOL (endPosn t) []
  275. lolCons :: a -> LOL a -> LOL a
  276. lolCons x (LOL p xs) = LOL p (x:xs)
  277. makeTupleType [x] =
  278. case x of
  279. SPType ParenType{} _ _ -> x
  280. _ -> ParenType x
  281. makeTupleType xs = Tytup xs
  282. makeTuplePattern [x] =
  283. case x of
  284. SPPat ParenPat{} _ _ -> x
  285. _ -> ParenPat x
  286. makeTuplePattern xs = TupPat xs
  287. makeTuple [x] =
  288. case x of
  289. SPExpr ParenExp{} _ _ -> x
  290. _ -> ParenExp x
  291. makeTuple xs = Tuple xs
  292. spanModuleItems xs = do
  293. let
  294. isImport (ModImport _ _ _) = True
  295. isImport _ = False
  296. (imports, items) = Prelude.span isImport xs
  297. forM_ items $ \x -> case x of
  298. ModImport _ start end ->
  299. alexThrow $ \fname ->
  300. ParseError { parseErrorMessage = "all import statements should be at the top of the file."
  301. , parseErrorInlineDesc = Just "unexpected import statement"
  302. , parseErrorFilename = fname
  303. , parseErrorBegin = start
  304. , parseErrorEnd = end
  305. }
  306. _ -> pure ()
  307. pure (map itemImport imports, items)
  308. tupleConSymName :: Int -> T.Text
  309. tupleConSymName n = T.singleton '(' <> T.replicate n (T.singleton ',') <> T.singleton ')'
  310. endOfListPos :: HasPosn x => x -> [x] -> Posn
  311. endOfListPos x [] = endPosn x
  312. endOfListPos _ xs = endPosn (last xs)
  313. }