Parser.hs 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. {-# LANGUAGE OverloadedStrings #-}
  2. module Potrero.Parser where
  3. import qualified Data.Char as Char
  4. import qualified Data.Text as Text
  5. import Potrero.Types
  6. data LineType
  7. = TableDecl Int Text.Text
  8. | TableEntry Range Result
  9. deriving (Eq, Show)
  10. indentAmount :: Text.Text -> Int
  11. indentAmount = Text.length . Text.takeWhile Char.isSpace
  12. parseRange :: Text.Text -> Range
  13. parseRange t
  14. | Text.all Char.isNumber (Text.strip t) =
  15. let n = read (Text.unpack t) in Range n n
  16. | otherwise =
  17. let (x, y) = Text.breakOn "-" (Text.strip t)
  18. n = read (Text.unpack x)
  19. m = read (Text.unpack (Text.tail y))
  20. in Range n m
  21. parseFragments :: Text.Text -> [Fragment]
  22. parseFragments t =
  23. let (frag, roll) = Text.breakOn "@{" t
  24. in case roll of
  25. "" -> [FragText frag]
  26. _ ->
  27. let (name, rest) = Text.breakOn "}" (Text.drop 2 roll)
  28. in FragText frag : FragRoll name : parseFragments (Text.tail rest)
  29. parseLines :: [Text.Text] -> [LineType]
  30. parseLines = go
  31. where
  32. go [] = []
  33. go (t:ts)
  34. | Text.all Char.isSpace t = go ts
  35. | Text.any (== ':') t =
  36. let (rangeTxt, message) = Text.breakOn ":" t
  37. range = parseRange rangeTxt
  38. msg = parseFragments (Text.tail message)
  39. in TableEntry range (Result msg) : go ts
  40. | otherwise =
  41. TableDecl (indentAmount t) (Text.strip t) : go ts
  42. parseTable :: Text.Text -> [Table]
  43. parseTable = parseTop [] . parseLines . Text.lines
  44. where
  45. parseTop _ [] = []
  46. parseTop ctx (TableDecl n name:xs) =
  47. parseTop ((n, name) : [ c | c <- ctx, fst c < n]) xs
  48. parseTop ctx (TableEntry r m:xs) =
  49. let (table, rest) = gatherEntries ctx xs [(r, m)]
  50. in table : parseTop ctx rest
  51. gatherEntries ctx (TableEntry r m:xs) es =
  52. gatherEntries ctx xs ((r, m) : es)
  53. gatherEntries ctx rs es =
  54. let name = Text.intercalate "/" (reverse (map snd ctx))
  55. in (Table name (reverse es), rs)