-- Scanner for simple expressions.
-- Developed for use in COMP2600
-- Clem Baker-Finch

module Scanner (Token(..), scan, unscan) where

import Data.Char

data Token = NUM Int
           | PLUS | MINUS | TIMES
           | LPAREN | RPAREN deriving (Eq, Show)

-- The scan function returns a list of tokens.

scan :: String -> [Token]

scan []           = []
scan ('+'    :cs) = PLUS      : scan cs
scan ('-'    :cs) = MINUS     : scan cs
scan ('*'    :cs) = TIMES     : scan cs
scan ('('    :cs) = LPAREN    : scan cs
scan (')'    :cs) = RPAREN    : scan cs
scan input@(c:cs)
    | isSpace c   = scan cs
    | isDigit c   = NUM (read num) : scan afterNum
    | otherwise   = error (c:" : illegal character.")
    where
    (num,  afterNum)  = span isDigit input


-- For better error messages, convert tokens back to strings.
-- Some redundancy?

unscan :: Token -> String

unscan (NUM n)   = "Numeral " ++ show n
unscan PLUS      = "+"
unscan MINUS     = "-"
unscan TIMES     = "*"
unscan LPAREN    = "("
unscan RPAREN    = ")"

