]> git.rmz.io Git - my-scheme.git/commitdiff
Support #bodx in number parser
authorSamir Benmendil <me@rmz.io>
Sun, 21 Jan 2018 00:56:01 +0000 (00:56 +0000)
committerSamir Benmendil <me@rmz.io>
Sun, 21 Jan 2018 00:56:01 +0000 (00:56 +0000)
`where radix = ...` returns a function that takes a number and parses it
accordingly. The function is chosed by 'try'ing to read a '#' followed
by any of "bodx" and if that fails assume the base is decimal.

The `>>` sequencing operator is used to combine `char` and `oneOf`, they
are executed one after another, discarding the value of the first.

`readInt` takes a base (2), a predicate returning what chars are valid
and a function that describes the Integer value for a char.
`(\x -> elem x "01")` is a lambda that returns true if x is in "01".

`(read . (:[]))` is interesting. The `.` operator composes the functions
`read` and `:[]`, where `:` is the append to list function and `[]` is
the "first argument", i.e. `:[]` appends an element to the empty list.

`let ((a,_):_) = ...` extracts the number from the `[(Number,String)]`
type returned by the `read*` functions.

Because strings starting with '#' are valid Atoms as well, we need to
parse for numbers first.

app/Main.hs

index 533d260b5c65528c845334d06ab704f5093fe9de..c71126b500c4a581a4e6d2bf61577352bd89cd1b 100644 (file)
@@ -2,6 +2,7 @@ module Main where
 import Control.Monad
 import Text.ParserCombinators.Parsec hiding (spaces)
 import System.Environment
+import Numeric
 
 data LispVal = Atom String
              | List [LispVal]
@@ -44,14 +45,21 @@ parseAtom = do
                 _    -> Atom atom
 
 parseNumber :: Parser LispVal
-parseNumber = do ds <- many1 digit
-                 let a = read ds
+parseNumber = do toNum <- radix
+                 ds <- many1 digit
+                 let ((a,_):_) = toNum ds
                  return $ Number a
+              where radix = do r <- try (char '#' >> oneOf "bodx") <|> return 'd'
+                               return $ case r of
+                                           'd' -> readDec
+                                           'x' -> readHex
+                                           'o' -> readOct
+                                           'b' -> readInt 2 (\x -> elem x "01") (read . (:[]))
 
 parseExpr :: Parser LispVal
 parseExpr = parseString
-        <|> parseAtom
         <|> parseNumber
+        <|> parseAtom
 
 readExpr :: String -> String
 readExpr input = case parse parseExpr "lisp" input of