@@ -22,19 +22,19 @@ import Prelude
2222
2323import Data.Array (elem , notElem )
2424import Data.CodePoint.Unicode (isAlpha , isAlphaNum , isDecDigit , isHexDigit , isLower , isOctDigit , isSpace , isUpper )
25- import Data.Either (Either (..))
25+ import Data.Either (Either (..), either )
2626import Data.Int as Data.Int
2727import Data.Maybe (Maybe (..))
2828import Data.Number (infinity , nan )
2929import Data.Number as Data.Number
3030import Data.String (CodePoint , singleton , takeWhile )
3131import Data.String.CodePoints (codePointFromChar )
3232import Data.String.CodeUnits as SCU
33- import Data.Tuple (Tuple (..), fst )
33+ import Data.Tuple (fst )
3434import Parsing (ParserT , fail )
35- import Parsing.Combinators (choice , skipMany , (<?>), (<~?>))
36- import Parsing.String (consumeWith , match , satisfy , satisfyCodePoint )
37- import Parsing.String as Parser.String
35+ import Parsing.Combinators (choice , tryRethrow , (<?>), (<| >), (<~?>))
36+ import Parsing.String (consumeWith , match , regex , satisfy , satisfyCodePoint , string )
37+ import Partial.Unsafe ( unsafeCrashWith )
3838
3939-- | Parse a digit. Matches any char that satisfies `Data.CodePoint.Unicode.isDecDigit`.
4040digit :: forall m . ParserT String m Char
@@ -84,26 +84,27 @@ alphaNum = satisfyCP isAlphaNum <?> "letter or digit"
8484-- | * `"NaN"`
8585-- | * `"-Infinity"`
8686number :: forall m . ParserT String m Number
87- -- TODO because the JavaScript parseFloat function will successfully parse
88- -- a Number up until it doesn't understand something and then return
89- -- the partially parsed Number, this parser will sometimes consume more
90- -- String that it actually parses. Example "1..3" will parse as 1.0.
91- -- So this needs improvement.
9287number =
9388 choice
94- [ Parser.String .string " Infinity" *> pure infinity
95- , Parser.String .string " +Infinity" *> pure infinity
96- , Parser.String .string " -Infinity" *> pure (negate infinity)
97- , Parser.String .string " NaN" *> pure nan
98- , do
99- Tuple section _ <- Parser.String .match do
100- _ <- oneOf [ ' +' , ' -' , ' .' , ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ]
101- skipMany $ oneOf [ ' e' , ' E' , ' +' , ' -' , ' .' , ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ]
89+ [ string " Infinity" *> pure infinity
90+ , string " +Infinity" *> pure infinity
91+ , string " -Infinity" *> pure (negate infinity)
92+ , string " NaN" *> pure nan
93+ , tryRethrow $ do
94+ section <- numberRegex
10295 -- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat
10396 case Data.Number .fromString section of
104- Nothing -> fail $ " Could not parse Number " <> section
97+ Nothing -> fail $ " Number.fromString failed"
98+ -- Maybe this parser should set consumed flag if regex matches but fromString fails?
99+ -- But currently regex allows some illegal inputs, like "."
100+ -- Anyway this primitiv-ish parser should always backtrack on fail.
105101 Just x -> pure x
106- ]
102+ ] <|> fail " Expected Number"
103+
104+ numberRegex :: forall m . ParserT String m String
105+ numberRegex = either unsafeCrashWith identity $ regex pattern mempty
106+ where
107+ pattern = " [+-]?[0-9]*(\\ .[0-9]*)?([eE][+-]?[0-9]*(\\ .[0-9]*))?"
107108
108109-- | Parser based on the __Data.Int.fromString__ function.
109110-- |
@@ -114,17 +115,20 @@ number =
114115-- | * `"-3"`
115116-- | * `"+300"`
116117intDecimal :: forall m . ParserT String m Int
117- intDecimal = do
118- Tuple section _ <- Parser.String .match do
119- _ <- oneOf [ ' +' , ' -' , ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ]
120- skipMany $ oneOf [ ' 0' , ' 1' , ' 2' , ' 3' , ' 4' , ' 5' , ' 6' , ' 7' , ' 8' , ' 9' ]
118+ intDecimal = tryRethrow do
119+ section <- intDecimalRegex <|> fail " Expected Int"
121120 case Data.Int .fromString section of
122- Nothing -> fail $ " Could not parse Int " <> section
121+ Nothing -> fail $ " Int.fromString failed "
123122 Just x -> pure x
124123
124+ intDecimalRegex :: forall m . ParserT String m String
125+ intDecimalRegex = either unsafeCrashWith identity $ regex pattern mempty
126+ where
127+ pattern = " [+-]?[0-9]*"
128+
125129-- | Helper function
126130satisfyCP :: forall m . (CodePoint -> Boolean ) -> ParserT String m Char
127- satisfyCP p = Parser.String . satisfy (p <<< codePointFromChar)
131+ satisfyCP p = satisfy (p <<< codePointFromChar)
128132
129133-- | Match zero or more whitespace characters satisfying
130134-- | `Data.CodePoint.Unicode.isSpace`. Always succeeds.
0 commit comments