From 4399097564c041838140225f30dcda7f92caa88a Mon Sep 17 00:00:00 2001 From: Joris Date: Wed, 10 May 2017 10:29:30 +0200 Subject: Add tests for purescript number and parser utilities --- js/src/Parser.purs | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 js/src/Parser.purs (limited to 'js/src/Parser.purs') diff --git a/js/src/Parser.purs b/js/src/Parser.purs new file mode 100644 index 0000000..cad9f1b --- /dev/null +++ b/js/src/Parser.purs @@ -0,0 +1,76 @@ +module Parser + ( TextWithNumber + , textWithNumber + , number + ) where + +import Control.Alt ((<|>)) +import Data.Array as Array +import Data.Char as Char +import Data.Either (Either(Right)) +import Data.Int as Int +import Data.Maybe (fromMaybe) as Maybe +import Data.Maybe (Maybe(Just, Nothing)) +import Data.String as String +import Prelude +import Text.Parsing.Parser (Parser) +import Text.Parsing.Parser (runParser) as Parser +import Text.Parsing.Parser.Combinators (optionMaybe) as Parser +import Text.Parsing.Parser.String (satisfy, anyChar, string, eof) as Parser + +type TextWithNumber = + { begin :: String + , number :: Number + , end :: String + } + +textWithNumber :: String -> Maybe TextWithNumber +textWithNumber input = + case Parser.runParser input textWithNumberParser of + Right x -> Just x + _ -> Nothing + +number :: String -> Maybe Number +number input = + case Parser.runParser input (numberParser <* Parser.eof) of + Right x -> Just x + _ -> Nothing + +textWithNumberParser :: Parser String TextWithNumber +textWithNumberParser = do + begin <- String.fromCharArray <$> Array.many notDigit + num <- numberParser + end <- String.fromCharArray <$> Array.many Parser.anyChar + pure { begin: begin, number: num, end: end } + +numberFromIntArray :: Array Int -> Int +numberFromIntArray xs = + Array.range 0 (Array.length xs - 1) + # map (Int.pow 10) + # Array.reverse + # Array.zipWith (*) xs + # Array.foldl (+) 0 + +notDigit :: Parser String Char +notDigit = Parser.satisfy (not <<< isDigit) + +numberParser :: Parser String Number +numberParser = do + whole <- numberFromIntArray <$> Array.some digit + decimal <- Parser.optionMaybe $ do + _ <- Parser.string "," <|> Parser.string "." + digits <- Array.some digit + let decimals = numberFromIntArray digits + pure $ Int.toNumber decimals / Int.toNumber (Int.pow 10 (Array.length digits)) + pure (Int.toNumber whole + Maybe.fromMaybe 0.0 decimal) + +digit :: Parser String Int +digit = map (\c -> Char.toCharCode c - zeroCode) $ Parser.satisfy isDigit + +isDigit :: Char -> Boolean +isDigit char = + let code = Char.toCharCode char + in code >= zeroCode && code <= zeroCode + 9 + +zeroCode :: Int +zeroCode = 48 -- cgit v1.2.3