aboutsummaryrefslogtreecommitdiff
path: root/js/Parser.purs
diff options
context:
space:
mode:
Diffstat (limited to 'js/Parser.purs')
-rw-r--r--js/Parser.purs76
1 files changed, 76 insertions, 0 deletions
diff --git a/js/Parser.purs b/js/Parser.purs
new file mode 100644
index 0000000..cad9f1b
--- /dev/null
+++ b/js/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