hascheme/y.hs

173 lines
5 KiB
Haskell
Raw Normal View History

2013-07-16 21:04:20 +00:00
module Main where
2013-07-18 08:47:46 +00:00
import Control.Monad (liftM)
2013-07-16 21:04:20 +00:00
import Data.List (foldl')
import Text.ParserCombinators.Parsec hiding (spaces)
import System.Environment (getArgs)
2013-07-18 08:14:26 +00:00
-- The possible LISP values
2013-07-16 21:04:20 +00:00
data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
2013-07-18 08:14:26 +00:00
| Float Float
2013-07-16 21:04:20 +00:00
| Number Integer
2013-07-17 20:45:03 +00:00
| Character Char
2013-07-16 21:04:20 +00:00
| String String
| Bool Bool
deriving (Show)
2013-07-18 08:14:26 +00:00
-- The program (in IO)
-- execute the arguments given in parameters
main :: IO ()
main = do
args <- getArgs
putStrLn (readExpr (args !!0))
-- ReadExpr will take a program as input
-- and will return the result of a parseExpr
readExpr :: String -> String
readExpr input = case parse parseExpr "lisp" input of
Left err -> "No match: " ++ show err
2013-07-18 16:55:18 +00:00
Right val -> showVal val
showVal :: LispVal -> String
showVal (String contents) = "\"" ++ contents ++ "\""
showVal (Atom name) = name
showVal (Number contents) = show contents
showVal (Float contents) = show contents
showVal (Character c) = '\'':c:'\'':[]
showVal (Bool True) = "#t"
showVal (Bool False) = "#f"
2013-07-18 08:14:26 +00:00
-- parseExpr will parse the Expression
parseExpr :: Parser LispVal
parseExpr = parseString
<|> try parseChar -- #\a #\b etc...
<|> try parseFloat -- 3.1415
<|> parseNumber -- 3, #b011001, #o070, #d930, #xFF3
<|> parseAtom -- symbol-323
2013-07-18 08:47:46 +00:00
<|> parseQuoted
<|> do
char '('
x <- try parseList <|> parseDottedList
char ')'
return x
2013-07-18 08:14:26 +00:00
2013-07-16 21:04:20 +00:00
symbol :: Parser Char
symbol = oneOf "!#$%&|*+-/:<=>?@^_~"
spaces :: Parser ()
spaces = skipMany1 space
2013-07-17 20:45:03 +00:00
parseChar :: Parser LispVal
parseChar = do
string "#\\"
c <- anyChar
return $ Character c
2013-07-16 21:04:20 +00:00
parseString :: Parser LispVal
parseString = do
char '"'
2013-07-17 20:30:02 +00:00
x <- many $ strSpecialChar <|> noneOf "\""
2013-07-16 21:04:20 +00:00
char '"'
return $ String x
2013-07-17 20:30:02 +00:00
where
strSpecialChar = char '\\' >> do
x <- anyChar
case x of
'n' -> return '\n'
't' -> return '\t'
'r' -> return '\r'
_ -> return x
2013-07-16 21:04:20 +00:00
parseAtom :: Parser LispVal
parseAtom = do
first <- letter <|> symbol
rest <- many (letter <|> digit <|> symbol)
let atom = first:rest
return $ case atom of
"#vrai" -> Bool True
"#faux" -> Bool False
_ -> Atom atom
numFromBase n str = foldl' traiteNombre 0 str
where
traiteNombre acc v = acc*n + chiffre
where chiffre = case v of
'0' -> 0
'1' -> 1
'2' -> 2
'3' -> 3
'4' -> 4
'5' -> 5
'6' -> 6
'7' -> 7
'8' -> 8
'9' -> 9
'A' -> 10
'B' -> 11
'C' -> 12
'D' -> 13
'E' -> 14
'F' -> 15
'a' -> 10
'b' -> 11
'c' -> 12
'd' -> 13
'e' -> 14
'f' -> 15
parseBaseSpecifiedNumber :: Parser Integer
parseBaseSpecifiedNumber = do
_ <- char '#'
numtype <- oneOf "bdox"
(base,str) <- case numtype of
'b' -> do
numstr <- many1 (oneOf "01")
return (2,numstr)
'o' -> do
numstr <- many1 (oneOf "01234567")
return (8,numstr)
'd' -> do
numstr <- many1 (oneOf "0123456789")
return (10,numstr)
'x' -> do
numstr <- many1 (oneOf "0123456789ABCDEFabcdef")
return (16,numstr)
return $ numFromBase base str
parseSimpleNumber :: Parser Integer
parseSimpleNumber = do
numStr <- many1 digit
return (read numStr)
2013-07-18 08:14:26 +00:00
parseFloat :: Parser LispVal
parseFloat = do
numBeforeDot <- many1 digit
char '.'
numAfterDot <- many1 digit
return $ Float (read (numBeforeDot ++ "." ++ numAfterDot))
2013-07-16 21:04:20 +00:00
parseNumber :: Parser LispVal
parseNumber = do
number <- parseSimpleNumber
<|> parseBaseSpecifiedNumber
return (Number number)
2013-07-18 08:47:46 +00:00
-- Recursive Parsers
parseList :: Parser LispVal
parseList = liftM List $ sepBy parseExpr spaces
parseDottedList :: Parser LispVal
parseDottedList = do
head <- endBy parseExpr spaces
tail <- char '.' >> spaces >> parseExpr
return $ DottedList head tail
parseQuoted :: Parser LispVal
parseQuoted = do
char '\''
x <- parseExpr
return $ List [Atom "quote", x]