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.

111 lines
3.2 KiB

  1. -- {-# LANGUAGE BlockArguments #-}
  2. module Main where
  3. import Control.Monad ( unless )
  4. import qualified Data.ByteString.Lazy as Lbs
  5. import qualified Data.Text.Encoding as T
  6. import qualified Data.Text as T
  7. import Data.Foldable
  8. import Debug.Trace
  9. import Frontend.Autogen.Parser
  10. import Frontend.Autogen.Lexer
  11. import Frontend.Lexer.Wrapper
  12. import Frontend.Lexer.Tokens
  13. import System.Environment (getArgs)
  14. import Text.Show.Pretty (pPrint)
  15. import Frontend.Parser.Posn
  16. import System.Posix.Internals
  17. import GHC.IO.Handle.FD (stdout, handleToFd)
  18. import GHC.IO.FD
  19. import Data.Maybe (fromMaybe)
  20. main :: IO ()
  21. main = do
  22. args <- getArgs
  23. for_ args $ \str -> do
  24. Main.lex str (\_ -> putStrLn $ str ++ " parsed!") parseMod =<< Lbs.readFile str
  25. testParse :: String -> IO ()
  26. testParse s = Main.lex "<interactive>" pPrint parseMod (Lbs.fromStrict (T.encodeUtf8 (T.pack s)))
  27. testLex :: String -> IO ()
  28. testLex s = Main.lex "<interactive>" (const (pure ())) (scan []) (Lbs.fromStrict (T.encodeUtf8 (T.pack s)))
  29. lex :: String -> (a -> IO ()) -> Alex a -> Lbs.ByteString -> IO ()
  30. lex fname show cont arg = do
  31. let
  32. x = runAlex fname arg cont
  33. color <- fmap (1 ==) . c_isatty . fdFD =<< handleToFd GHC.IO.Handle.FD.stdout
  34. code <- if fname == "<interactive>"
  35. then pure . lines $ T.unpack (T.decodeUtf8 (Lbs.toStrict arg))
  36. else lines <$> readFile fname
  37. case x of
  38. Left e -> putStr $ showParseError color code e
  39. Right x -> show x
  40. printParseError :: ParseError -> IO ()
  41. printParseError pe = do
  42. code <- lines <$> readFile (parseErrorFilename pe)
  43. color <- fmap (1 ==) . c_isatty . fdFD =<< handleToFd GHC.IO.Handle.FD.stdout
  44. putStr $ showParseError color code pe
  45. showParseError :: Bool -> [String] -> ParseError -> String
  46. showParseError color code pe = do
  47. let
  48. linum = posnLine (parseErrorBegin pe)
  49. startcol = posnColm (parseErrorBegin pe)
  50. multiline = linum /= posnLine (parseErrorEnd pe)
  51. width
  52. | multiline = 0
  53. | otherwise = max 0 (posnColm (parseErrorEnd pe) - startcol - 1)
  54. linum' = show linum
  55. line = [ show linum ++ sep ++ code !! (linum - 1) | linum <- [ linum .. posnLine (parseErrorEnd pe) ] ]
  56. padding = replicate (length linum') ' ' ++ sep
  57. padding' = replicate (length linum') ' ' ++ " "
  58. caret = replicate (startcol - 1) ' ' ++ red ++ "^"
  59. squiggle = replicate width '~'
  60. (red, bold, reset, sep)
  61. | color = ("\x1b[31m", "\x1b[1m", "\x1b[0m", "\x1b[1;34m \9474 \x1b[0m")
  62. | otherwise = ("", "", "", "")
  63. unlines $
  64. [ bold
  65. ++ parseErrorFilename pe
  66. ++ ":" ++ show linum ++ ":" ++ show startcol ++ ": "
  67. ++ red ++ "parse error:" ++ reset
  68. , padding'
  69. , init (unlines line)
  70. , padding' ++ caret ++ squiggle ++ reset ++ fromMaybe "" ((" " ++) <$> parseErrorInlineDesc pe)
  71. , ""
  72. , padding' ++ parseErrorMessage pe
  73. ]
  74. scan :: [Token] -> Alex [Token]
  75. scan acc = do
  76. tok <- alexMonadScan
  77. sc <- alexGetStartCode
  78. state <- getUserState
  79. traceM . unlines $
  80. [ "----------------"
  81. , "just lexed: " ++ show tok
  82. , "sc: " ++ show sc
  83. , "sc stack: " ++ show (startCodes state)
  84. , "layout stack: " ++ show (layoutColumns state)
  85. ]
  86. case tokenClass tok of
  87. TokEof -> pure (reverse acc)
  88. _ -> scan (tok:acc)