packages feed

vintage-basic-1.0.3: src/Language/VintageBasic/FloatParser.hs

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

-- | Code for parsing floats. Used both in parsing static code and at runtime
-- (@INPUT@ and @DATA@ statements).

module Language.VintageBasic.FloatParser(FloatParser(..)) where

import Data.Char(isDigit)
import Text.ParserCombinators.Parsec
import Language.VintageBasic.LexCommon(Tagged,getTaggedVal)
import Language.VintageBasic.Tokenizer(Token(..),tokenP,charTokTest)

-- | Generic class for float parsers. Can be used to parse floats from raw
-- characters (useful at runtime) or from tokenized text (for parsing source).
class FloatParser tok st where
    digitP :: GenParser tok st Char
    dotP   :: GenParser tok st Char
    plusP  :: GenParser tok st Char
    minusP :: GenParser tok st Char
    charEP :: GenParser tok st Char

    floatP :: GenParser tok st Float
    floatP = do
        sgn <- option "" sgnP
        mant <- try float2P <|> float1P
        expt <- option "" expP
        return (read (sgn++mant++expt))

    float1P :: GenParser tok st String
    float1P = many1 digitP

    float2P :: GenParser tok st String
    float2P = do
        i <- many digitP
        _ <- dotP
        f <- many digitP
        return ("0"++i++"."++f++"0")

    sgnP :: GenParser tok st String
    sgnP = do
        sgn <- plusP <|> minusP
        return (if sgn == '+' then "" else "-")

    expP :: GenParser tok st String
    expP = do
        _ <- charEP
        esgn <- option "" sgnP
        i <- many1 digitP
        return ("E"++esgn++i)

instance FloatParser Char st where
    digitP = digit
    dotP   = char '.'
    plusP  = char '+'
    minusP = char '-'
    charEP = char 'E' <|> char 'e'

instance FloatParser (Tagged Token) () where
    digitP = do tok <- tokenP (charTokTest isDigit)
                return (getCharTokChar $ getTaggedVal tok)
    dotP   = tokenP (==DotTok)            >> return '.'
    plusP  = tokenP (==PlusTok)           >> return '+'
    minusP = tokenP (==MinusTok)          >> return '-'
    charEP = tokenP (charTokTest (=='E')) >> return 'E'