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.

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