/R5RS/SyntaxTree.hs

https://github.com/haxis-fx/R5RS-Haskell · Haskell · 389 lines · 281 code · 58 blank · 50 comment · 38 complexity · bd4d232242224f4a7866dc1ecb57fe0a MD5 · raw file

  1. module R5RS.SyntaxTree (
  2. readExpr,
  3. readExprList
  4. ) where
  5. import Char
  6. import Complex
  7. import Control.Monad
  8. import Control.Monad.Error
  9. import Data.Ratio
  10. import Numeric
  11. import Text.ParserCombinators.Parsec
  12. import R5RS.LispTypes
  13. --------------------
  14. readExpr = readOrThrow parseExpr'
  15. where parseExpr' = do e <- spaces >> parseExpr
  16. spaces >> eof
  17. return e
  18. readExprList = readOrThrow parseExprs
  19. where parseExprs = do es <- spaces >> parseExpr `sepEndBy` spaces1
  20. eof
  21. return es
  22. ---------------------
  23. empty :: GenParser tok st [a]
  24. empty = return []
  25. {--
  26. zero1 :: GenParser tok st a -> GenParser tok st [a]
  27. zero1 p = count 1 p <|> empty
  28. --}
  29. symbol :: Parser Char
  30. symbol = oneOf "!$%&|*+-/:<=>?@^_~"
  31. spaces1 :: Parser ()
  32. spaces1 = skipMany1 space
  33. parseAtom :: Parser LispVal
  34. parseAtom = do first <- letter <|> symbol
  35. rest <- many (letter <|> digit <|> symbol)
  36. return $ Atom (first:rest)
  37. parseBool :: Parser LispVal
  38. parseBool = do try $ char '#'
  39. x <- oneOf "tTfF"
  40. return $ case toLower x of 't' -> Bool True
  41. 'f' -> Bool False
  42. _ -> error "Will not come here"
  43. --------------------------------------------------------------------------------
  44. -- <character> -> #\ <any character>
  45. -- | #\ <any character name>
  46. -- <character name> -> space | newline
  47. --------------------------------------------------------------------------------
  48. parseChar :: Parser LispVal
  49. parseChar = do string "#\\"
  50. (try (string "space" >> (return $ Char ' ')) <|>
  51. try (string "newline" >> (return $ Char '\n')) <|>
  52. (anyChar >>= return . Char))
  53. --------------------------------------------------------------------------------
  54. -- <string> -> " <string element>* "
  55. -- <string element> -> <any character other than " or \> | \" | \\
  56. --------------------------------------------------------------------------------
  57. escapedChars :: Parser Char
  58. escapedChars = do char '\\'
  59. x <- oneOf "\\\"nrt"
  60. return $ case x of
  61. '\\' -> x
  62. '"' -> x
  63. 'n' -> '\n'
  64. 'r' -> '\r'
  65. 't' -> '\t'
  66. _ -> error ("Not a supported backslash char: " ++ [x])
  67. parseString :: Parser LispVal
  68. parseString = do char '"'
  69. x <- many $ escapedChars <|> noneOf "\"\\"
  70. char '"'
  71. return $ String x
  72. --------------------------------------------------------------------------------
  73. -- <prefix R> -> <radix R> <exactness>
  74. -- | <exactness> <radix R>
  75. -- <exactness> -> <empty> | #i | #e
  76. -- <radix 2> -> #b
  77. -- <radix 8> -> #o
  78. -- <radix 10> -> <empty> | #d
  79. -- <radix 16> -> #x
  80. --------------------------------------------------------------------------------
  81. exactness :: String -> Parser String
  82. exactness s = try (do s0 <- do e0 <- char '#'
  83. e1 <- oneOf exactStr
  84. return $ [e0, toLower e1]
  85. s1 <- do r0 <- char '#'
  86. r1 <- oneOf s
  87. return $ [r0, toLower r1]
  88. return $ s0 ++ s1)
  89. <|>
  90. try (do s0 <- do r0 <- char '#'
  91. r1 <- oneOf s
  92. return $ [r0, toLower r1]
  93. s1 <- do e0 <- char '#'
  94. e1 <- oneOf exactStr
  95. return $ [e0, toLower e1]
  96. return $ s0 ++ s1)
  97. <|>
  98. try (do s0 <- do r0 <- char '#'
  99. r1 <- oneOf s
  100. return $ [r0, toLower r1]
  101. return s0)
  102. <|>
  103. try (do s1 <- do e0 <- char '#'
  104. e1 <- oneOf exactStr
  105. return $ [e0, toLower e1]
  106. return s1)
  107. <|> empty
  108. where exactStr = "iIeE"
  109. --------------------------------------------------------------------------------
  110. -- <sign> -> <empty> | + | -
  111. --------------------------------------------------------------------------------
  112. parseSign :: Num a => Parser a
  113. parseSign = do sign <- string "+" <|> string "-" <|> empty
  114. return (if '-' `elem` sign then -1 else 1)
  115. parseUIntDigitNE :: Num a => (ReadS a, Parser Char) -> Parser a
  116. parseUIntDigitNE (reader, digits) = do x0 <- many1 digits
  117. return $ fst $ reader x0 !! 0
  118. {--
  119. parseIntDigitNE :: Num a => (ReadS a, Parser Char) -> Parser a
  120. parseIntDigitNE arg = do sign <- parseSign
  121. v <- parseUIntDigitNE arg
  122. return $ sign * v
  123. --}
  124. parseUIntDigit :: Num a => (ReadS a, Parser Char) -> Parser (a, Bool)
  125. parseUIntDigit arg = do v <- parseUIntDigitNE arg
  126. x <- many (char '#')
  127. let len = length x
  128. in return (v * 10 ^ len, len == 0)
  129. parseIntDigit :: Num a => (ReadS a, Parser Char) -> Parser (a, Bool)
  130. parseIntDigit arg = do sign <- parseSign
  131. (v, isExact) <- parseUIntDigit arg
  132. return (sign * v, isExact)
  133. --------------------------------------------------------------------------------
  134. -- <decimal 10> -> <uinteger 10> <suffix>
  135. -- | . <digit 10>+ #* <suffix>
  136. -- | <digit 10>+ . <digit 10>* #* <suffix>
  137. -- | <digit 10>+ #+ . #* <suffix>
  138. --------------------------------------------------------------------------------
  139. parseDecimal10 :: RealFrac a => Parser (a, Bool)
  140. parseDecimal10 = do char '.'
  141. x0 <- many1 digit
  142. x1 <- many (char '#')
  143. (e, _) <- parseExponent
  144. let l0 = length x0
  145. l1 = length x1
  146. v = fst $ readDec x0 !! 0
  147. in return (v * 10 ^ l1 * 10 ^^ (-(l0 + l1)) * e, False)
  148. <|> try (do (x, isExact1) <- parseUIntDigit (readDec, digit)
  149. (e, isExact2) <- parseExponentNE
  150. return (x * e, isExact1 && isExact2))
  151. <|> try (do x0 <- many1 digit
  152. char '.'
  153. x1 <- many digit
  154. x2 <- many (char '#')
  155. (e, _) <- parseExponent
  156. let v0 = fst $ readDec x0 !! 0
  157. l1 = length x1
  158. l2 = length x2
  159. v1 = if l1 > 0 then fst $ readDec x1 !! 0 else if l2 > 0 then 1 else 0
  160. in return ((v0 + v1 * 10 ^ l2 * 10 ^^ (-(l1 + l2))) * e, False))
  161. <|> do x0 <- many1 digit
  162. x1 <- many1 (char '#')
  163. char '.'
  164. many (char '#')
  165. (e, _) <- parseExponent
  166. let v0 = fst $ readDec x0 !! 0
  167. l1 = length x1
  168. in return ((v0 * 10 ^ l1) * e, False)
  169. parseSignedDecimal10 :: RealFrac a => Parser (a, Bool)
  170. parseSignedDecimal10 = do sign <- parseSign
  171. (v, isExact) <- parseDecimal10
  172. return (sign * v, isExact)
  173. --------------------------------------------------------------------------------
  174. -- <complex R> -> <real R> | <real R> @ <real R>
  175. -- | <real R> + <ureal R> i | <real R> - <ureal R> i
  176. -- | <real R> + i | <real R> - i
  177. -- | + <ureal R> i | - <ureal R> i | + i | - i
  178. --------------------------------------------------------------------------------
  179. parseUReal :: RealFrac a => Parser (a, Bool)
  180. parseUReal = try parseDecimal10 <|> parseUIntDigit (readDec, digit)
  181. parseReal :: RealFrac a => Parser (a, Bool)
  182. parseReal = do sign <- parseSign
  183. (v, isExact) <- parseUReal
  184. return (sign * v, isExact)
  185. parseComplex10 :: RealFloat a => Parser (Complex a, Bool)
  186. parseComplex10 = try (do (rel, isExact1) <- parseReal
  187. char '+'
  188. (img, isExact2) <- parseUReal
  189. char 'i'
  190. return (rel :+ img, isExact1 && isExact2))
  191. <|> try (do (rel, isExact1) <- parseReal
  192. char '-'
  193. (img, isExact2) <- parseUReal
  194. char 'i'
  195. return (rel :+ (-img), isExact1 && isExact2))
  196. <|> try (do (rel, isExact) <- parseReal
  197. string "+i"
  198. return (rel :+ 1, isExact))
  199. <|> try (do (rel, isExact) <- parseReal
  200. string "-i"
  201. return (rel :+ (-1), isExact))
  202. <|> try (do (len, isExact1) <- parseReal
  203. char '@'
  204. (rad, isExact2) <- parseReal
  205. return ((len * cos rad) :+ (len * sin rad), isExact1 && isExact2))
  206. <|> try (do char '+'
  207. (img, isExact) <- parseUReal
  208. char 'i'
  209. return (0 :+ img, isExact))
  210. <|> try (do char '-'
  211. (img, isExact) <- parseUReal
  212. char 'i'
  213. return (0 :+ (-img), isExact))
  214. <|> do string "+i"
  215. return (0 :+ 1, True)
  216. <|> do string "-i"
  217. return (0 :+ (-1), True)
  218. --------------------------------------------------------------------------------
  219. -- <suffix> -> <empty>
  220. -- | <exponent marker> <sign> <digit 10>+
  221. -- <exponent marker> -> e | s | f | d | l
  222. --------------------------------------------------------------------------------
  223. parseExponentNE :: RealFrac a => Parser (a, Bool)
  224. parseExponentNE = do oneOf "eEsSfFdDlL"
  225. sign <- parseSign
  226. v <- parseUIntDigitNE (readDec, digit)
  227. return ((10 ^^ (sign * v)), False)
  228. parseExponent :: RealFrac a => Parser (a, Bool)
  229. parseExponent = parseExponentNE <|> do empty
  230. return (1, True)
  231. isBinary :: Char -> Bool
  232. isBinary x | x == '0' = True
  233. | x == '1' = True
  234. | otherwise = False
  235. binDigit = satisfy isBinary <?> "binary digit"
  236. getParser :: Num a => String -> (ReadS a, Parser Char)
  237. getParser s = if 'b' `elem` s then (readInt 2 isBinary (\x -> case x of '0' -> 0
  238. '1' -> 1
  239. _ -> error "Will not come here" ), binDigit)
  240. else if 'o' `elem` s then (readOct, octDigit)
  241. else if 'x' `elem` s then (readHex, hexDigit)
  242. else (readDec, digit)
  243. radixStr = "dDbBoOxX"
  244. parseInt :: Parser LispVal
  245. parseInt = do prefix <- exactness radixStr
  246. (ret, isExact) <- parseIntDigit (getParser prefix)
  247. return $ Number (Integer ret)
  248. ('e' `elem` prefix || 'i' `notElem` prefix && isExact)
  249. parseRatio :: Parser LispVal
  250. parseRatio = do prefix <- exactness radixStr
  251. let r = getParser prefix
  252. (ret1, isExact1) <- parseIntDigit r
  253. char '/'
  254. (ret2, isExact2) <- parseUIntDigit r
  255. return $ Number (Rational (ret1 % ret2))
  256. ('e' `elem` prefix || 'i' `notElem` prefix && isExact1 && isExact2)
  257. parseFloat :: Parser LispVal
  258. parseFloat = do prefix <- exactness "dD"
  259. (ret, isExact) <- parseSignedDecimal10
  260. return $ Number (Float ret)
  261. ('e' `elem` prefix || 'i' `notElem` prefix && isExact)
  262. parseComplex :: Parser LispVal
  263. parseComplex = do prefix <- exactness "dD"
  264. (ret, isExact) <- parseComplex10
  265. return $ Number (Complex ret)
  266. ('e' `elem` prefix || 'i' `notElem` prefix && isExact)
  267. parseNumber :: Parser LispVal
  268. parseNumber = try parseComplex
  269. <|> try parseFloat
  270. <|> try parseRatio
  271. <|> parseInt
  272. parseList :: Parser LispVal
  273. parseList = liftM List $ parseExpr `sepEndBy` spaces1
  274. parseDottedPair :: Parser LispVal
  275. parseDottedPair = do head <- parseExpr `endBy` spaces1
  276. tail <- char '.' >> spaces1 >> parseExpr
  277. spaces
  278. case tail of List [Atom "unquote", _ ] -> return $ DottedPair head tail
  279. List [Atom "unquote-splicing", _ ] -> return $ DottedPair head tail
  280. List as -> return $ List (head ++ as)
  281. DottedPair [Atom "unquote", _ ] _ -> return $ DottedPair head tail
  282. DottedPair [Atom "unquote-splicing", _ ] _ -> return $ DottedPair head tail
  283. DottedPair as tail' -> return $ DottedPair (head ++ as) tail'
  284. _ -> return $ DottedPair head tail
  285. parseVector :: Parser LispVal
  286. parseVector = do string "#(" >> spaces
  287. es <- parseList
  288. char ')'
  289. return $ Vector es
  290. parseSExpr :: Parser LispVal
  291. parseSExpr = do char '(' >> spaces
  292. es <- try parseDottedPair <|> parseList
  293. char ')'
  294. return es
  295. parseEllipsisVar :: Parser LispVal
  296. parseEllipsisVar = do s <- parseAtom
  297. spaces1 >> string "..."
  298. return $ EllipsisVar s []
  299. parseQuoted :: Parser LispVal
  300. parseQuoted = do char '\''
  301. x <- parseExpr
  302. return $ List [Atom "quote", x]
  303. parseQuasiquoted :: Parser LispVal
  304. parseQuasiquoted = do char '`'
  305. x <- parseExpr
  306. return $ List [Atom "quasiquote", x]
  307. parseUnquoted :: Parser LispVal
  308. parseUnquoted = do char ','
  309. x <- parseExpr
  310. return $ List [Atom "unquote", x]
  311. parseUnquoteSplicing :: Parser LispVal
  312. parseUnquoteSplicing = do string ",@"
  313. x <- parseExpr
  314. return $ List [Atom "unquote-splicing", x]
  315. parseExpr :: Parser LispVal
  316. parseExpr = try parseBool
  317. <|> try parseChar
  318. <|> try parseNumber
  319. <|> try parseEllipsisVar
  320. <|> try parseUnquoteSplicing
  321. <|> parseUnquoted
  322. <|> parseQuasiquoted
  323. <|> parseQuoted
  324. <|> parseAtom
  325. <|> parseString
  326. <|> parseSExpr
  327. <|> parseVector
  328. readOrThrow :: Parser a -> String -> IOThrowsError a
  329. readOrThrow parser input = case parse parser "lisp" input of
  330. Left err -> throwError $ Parser err
  331. Right val -> return val