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.

129 lines
2.4 KiB

2 years ago
  1. {
  2. module Lexer where
  3. import Control.Monad.State
  4. import Control.Monad.Error
  5. import Lexer.Support
  6. import Debug.Trace
  7. }
  8. %encoding "latin1"
  9. $lower = [ a-z ]
  10. $upper = [ A-Z ]
  11. @ident = $lower [ $lower $upper _ ' ]*
  12. :-
  13. [\ \t]+ ;
  14. <0> "in" { token TkIn }
  15. <0> "let" { layoutKw TkLet }
  16. <0> "where" { layoutKw TkWhere }
  17. <0> @ident { emit TkIdent }
  18. <0> \\ { token TkBackslash }
  19. <0> "->" { token TkArrow }
  20. <0> \= { token TkEqual }
  21. <0> \( { token TkLParen }
  22. <0> \) { token TkRParen }
  23. <0> \{ { token TkOpen }
  24. <0> \} { token TkClose }
  25. <0> "--" .* \n { \_ -> pushStartCode newline *> scan }
  26. <0> \n { \_ -> pushStartCode newline *> scan }
  27. <layout> {
  28. -- Skip comments and whitespace
  29. "--" .* \n ;
  30. \n ;
  31. \{ { openBrace }
  32. () { startLayout }
  33. }
  34. <empty_layout> () { emptyLayout }
  35. <newline> {
  36. \n ;
  37. "--" .* \n ;
  38. () { offsideRule }
  39. }
  40. <eof> () { doEOF }
  41. {
  42. handleEOF = pushStartCode eof *> scan
  43. doEOF _ = do
  44. t <- Lexer.Support.layout
  45. case t of
  46. Nothing -> do
  47. popStartCode
  48. pure TkEOF
  49. _ -> do
  50. popLayout
  51. pure TkVClose
  52. scan :: Lexer Token
  53. scan = do
  54. input@(Input _ _ _ string) <- gets lexerInput
  55. startcode <- startCode
  56. case alexScan input startcode of
  57. AlexEOF -> handleEOF
  58. AlexError (Input _ _ _ inp) ->
  59. throwError $ "Lexical error: " ++ show (head inp)
  60. AlexSkip input' _ -> do
  61. modify' $ \s -> s { lexerInput = input' }
  62. scan
  63. AlexToken input' tokl action -> do
  64. modify' $ \s -> s { lexerInput = input' }
  65. action (take tokl string)
  66. layoutKw t _ = do
  67. pushStartCode Lexer.layout
  68. pure t
  69. openBrace _ = do
  70. popStartCode
  71. pushLayout ExplicitLayout
  72. pure TkOpen
  73. startLayout _ = do
  74. popStartCode
  75. reference <- Lexer.Support.layout
  76. col <- gets (inpColumn . lexerInput)
  77. if Just (LayoutColumn col) <= reference
  78. then pushStartCode empty_layout
  79. else pushLayout (LayoutColumn col)
  80. pure TkVOpen
  81. emptyLayout _ = do
  82. popStartCode
  83. pushStartCode newline
  84. pure TkVClose
  85. offsideRule _ = do
  86. context <- Lexer.Support.layout
  87. col <- gets (inpColumn . lexerInput)
  88. let continue = popStartCode *> scan
  89. case context of
  90. Just (LayoutColumn col') -> do
  91. case col `compare` col' of
  92. EQ -> do
  93. popStartCode
  94. pure TkVSemi
  95. GT -> continue
  96. LT -> do
  97. popLayout
  98. pure TkVClose
  99. _ -> continue
  100. }