Basic.hs 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. {-# LANGUAGE OverloadedStrings #-}
  2. module Data.SCargot.Language.Basic
  3. ( -- * Spec
  4. -- $descr
  5. basicParser
  6. , basicPrinter
  7. , locatedBasicParser
  8. , locatedBasicPrinter
  9. ) where
  10. import Control.Applicative ((<$>))
  11. import Data.Char (isAlphaNum)
  12. import Text.Parsec (many1, satisfy)
  13. import Data.Text (Text, pack)
  14. import Data.Functor.Identity (Identity)
  15. import Text.Parsec.Prim (ParsecT)
  16. import Data.SCargot.Common (Located(..), located)
  17. import Data.SCargot.Repr.Basic (SExpr)
  18. import Data.SCargot ( SExprParser
  19. , SExprPrinter
  20. , mkParser
  21. , flatPrint
  22. )
  23. isAtomChar :: Char -> Bool
  24. isAtomChar c = isAlphaNum c
  25. || c == '-' || c == '*' || c == '/'
  26. || c == '+' || c == '<' || c == '>'
  27. || c == '=' || c == '!' || c == '?'
  28. pToken :: ParsecT Text a Identity Text
  29. pToken = pack <$> many1 (satisfy isAtomChar)
  30. -- $descr
  31. -- The 'basicSpec' describes S-expressions whose atoms are simply
  32. -- text strings that contain alphanumeric characters and a small
  33. -- set of punctuation. It does no parsing of numbers or other data
  34. -- types, and will accept tokens that typical Lisp implementations
  35. -- would find nonsensical (like @77foo@).
  36. --
  37. -- Atoms recognized by the 'basicSpec' are any string matching the
  38. -- regular expression @[A-Za-z0-9+*<>/=!?-]+@.
  39. -- | A 'SExprParser' that understands atoms to be sequences of
  40. -- alphanumeric characters as well as the punctuation
  41. -- characters @[-*/+<>=!?]@, and does no processing of them.
  42. --
  43. -- >>> decode basicParser "(1 elephant)"
  44. -- Right [SCons (SAtom "1") (SCons (SAtom "elephant") SNil)]
  45. basicParser :: SExprParser Text (SExpr Text)
  46. basicParser = mkParser pToken
  47. -- | A 'basicParser' which produces 'Located' values
  48. --
  49. -- >>> decode locatedBasicParser $ pack "(1 elephant)"
  50. -- Right [SCons (SAtom (At (Span (line 1, column 2) (line 1, column 3)) "1")) (SCons (SAtom (At (Span (line 1, column 4) (line 1, column 12)) "elephant")) SNil)]
  51. --
  52. -- >>> decode locatedBasicParser $ pack "(let ((x 1))\n x)"
  53. -- Right [SCons (SAtom (At (Span (line 1, column 2) (line 1, column 5)) "let")) (SCons (SCons (SCons (SAtom (At (Span (line 1, column 8) (line 1, column 9)) "x")) (SCons (SAtom (At (Span (line 1, column 10) (line 1, column 11)) "1")) SNil)) SNil) (SCons (SAtom (At (Span (line 2, column 3) (line 2, column 4)) "x")) SNil))]
  54. locatedBasicParser :: SExprParser (Located Text) (SExpr (Located Text))
  55. locatedBasicParser = mkParser $ located pToken
  56. -- | A 'SExprPrinter' that prints textual atoms directly (without quoting
  57. -- or any other processing) onto a single line.
  58. --
  59. -- >>> encode basicPrinter [L [A "1", A "elephant"]]
  60. -- "(1 elephant)"
  61. basicPrinter :: SExprPrinter Text (SExpr Text)
  62. basicPrinter = flatPrint id
  63. -- | A 'SExprPrinter' for 'Located' values. Works exactly like 'basicPrinter'
  64. -- It ignores the location tags when printing the result.
  65. --
  66. -- >>> let (Right dec) = decode locatedBasicParser $ pack "(1 elephant)"
  67. -- [SCons (SAtom (At (Span (line 1, column 2) (line 1, column 3)) "1")) (SCons (SAtom (At (Span (line 1, column 4) (line 1, column 12)) "elephant")) SNil)]
  68. --
  69. -- >>> encode locatedBasicPrinter dec
  70. -- "(1 elephant)"
  71. locatedBasicPrinter :: SExprPrinter (Located Text) (SExpr (Located Text))
  72. locatedBasicPrinter = flatPrint unLoc
  73. where unLoc (At _loc e) = e