@@ -12,11 +12,13 @@ module Parse.Primitives
12 , Space(..), whitespace
12 , Space(..), whitespace
13 , docComment
13 , docComment
14 , string, character
14 , string, character
15− , digit
15+ , digit, number
19import Prelude hiding (length)
19import Prelude hiding (length)
20+import qualified Control.Applicative as Applicative ( Applicative(..), Alternative(..) )
20import qualified Data.Char as Char
22import qualified Data.Char as Char
21import qualified Data.Set as Set
23import qualified Data.Set as Set
22import Data.Text (Text)
24import Data.Text (Text)
@@ -28,10 +30,10 @@ import qualified Data.Text.Lazy as LT
28import qualified Data.Text.Lazy.Builder as LB
30import qualified Data.Text.Lazy.Builder as LB
29import Data.Text.Internal.Encoding.Utf16 (chr2)
31import Data.Text.Internal.Encoding.Utf16 (chr2)
30import Data.Text.Internal.Unsafe.Char (unsafeChr)
32import Data.Text.Internal.Unsafe.Char (unsafeChr)
31−import qualified Control.Applicative as Applicative ( Applicative(..), Alternative(..) )
33+import GHC.Word (Word16(..))
34import qualified AST.Helpers as Help (isSymbol)
35import qualified AST.Helpers as Help (isSymbol)
36+import qualified AST.Literal as L
35import qualified Reporting.Region as Region
37import qualified Reporting.Region as Region
@@ -774,13 +776,16 @@ eatHex array offset length n =
774character :: Parser Char
776character :: Parser Char
775character =
777character =
776 Parser $ \(State array offset length indent row col) cok cerr _ eerr ->
778 Parser $ \(State array offset length indent row col) cok cerr _ eerr ->
777− if length <= 3 then
779+ if length == 0 then
778 eerr (Error row col)
780 eerr (Error row col)
781 if Text.unsafeIndex array offset /= 0x0027 {- ' -} then
783 if Text.unsafeIndex array offset /= 0x0027 {- ' -} then
782 eerr (Error row col)
784 eerr (Error row col)
786+ else if length < 3 then
787+ cerr (Error row col)
785 case characterHelp array (offset + 1) (length - 1) row (col + 1) of
790 case characterHelp array (offset + 1) (length - 1) row (col + 1) of
786 Left err ->
791 Left err ->
@@ -826,7 +831,7 @@ characterHelp array offset length row col =
829−-- NUMBERS
834+-- DIGITS
832digit :: Parser Int
837digit :: Parser Int
@@ -838,11 +843,228 @@ digit =
840 !word = Text.unsafeIndex array offset
845 !word = Text.unsafeIndex array offset
841− !isDigit = word <= 0x0039 {- 9 -} && word >= 0x0030 {- 0 -}
843− if isDigit then
847+ if isDigit word then
845 (fromIntegral (word - 0x0030))
849 (fromIntegral (word - 0x0030))
846 (State array (offset + 1) (length - 1) indent row (col + 1))
850 (State array (offset + 1) (length - 1) indent row (col + 1))
848− eerr (Error row col)
852+ eerr (Error row col)
859+number :: Parser L.Literal
861+ Parser $ \(State array offset length indent row col) cok cerr _ eerr ->
863+ eerr (Error row col)
867+ !word = Text.unsafeIndex array offset
869+ if not (isDigit word) then
870+ eerr (Error row col)
875+ if word == 0x0030 {- 0 -} then
876+ chompZero array offset (offset + 1) (length - 1)
878+ chompInt array offset (offset + 1) (length - 1)
880+ case chompResults of
884+ Right (newOffset, newLength, literal) ->
885+ if isDirtyEnd array newOffset newLength then
886+ cerr (Error row col)
889+ cok literal (State array newOffset newLength indent row (col + (newOffset - offset)))
892+isDirtyEnd :: Text.Array -> Int -> Int -> Bool
893+isDirtyEnd array offset length =
899+ !char = peekChar array offset
901+ Char.isAlpha char || char == '_'
904+chompInt :: Text.Array -> Int -> Int -> Int -> Either Error (Int, Int, L.Literal)
905+chompInt array startOffset offset length =
908+ Right ( offset, length, readInt array startOffset offset )
913+ !word = Text.unsafeIndex array offset
915+ if isDigit word then
916+ chompInt array startOffset (offset + 1) (length - 1)
918+ else if word == 0x002E {- . -} then
919+ chompFraction array startOffset (offset + 1) (length - 1)
922+ Right ( offset, length, readInt array startOffset offset )
925+chompFraction :: Text.Array -> Int -> Int -> Int -> Either Error (Int, Int, L.Literal)
926+chompFraction array startOffset offset length =
928+ Left (error "TODO chompFraction")
930+ else if isDigit (Text.unsafeIndex array offset) then
931+ chompFractionHelp array startOffset (offset + 1) (length - 1)
934+ Left (error "TODO must be a number after a decimal point")
937+chompFractionHelp :: Text.Array -> Int -> Int -> Int -> Either Error (Int, Int, L.Literal)
938+chompFractionHelp array startOffset offset length =
940+ Right (offset, length, readFloat array startOffset offset)
944+ !word = Text.unsafeIndex array offset
946+ if isDigit word then
947+ chompFractionHelp array startOffset (offset + 1) (length - 1)
949+ else if word == 0x0065 {- e -} || word == 0x0045 {- E -} then
950+ chompExponent array startOffset (offset + 1) (length - 1)
953+ Right (offset, length, readFloat array startOffset offset)
956+chompExponent :: Text.Array -> Int -> Int -> Int -> Either Error (Int, Int, L.Literal)
957+chompExponent array startOffset offset length =
959+ Right (offset, length, readFloat array startOffset offset)
963+ !word = Text.unsafeIndex array offset
965+ if isDigit word then
966+ chompExponentHelp array startOffset (offset + 1) (length - 1)
968+ else if word == 0x002B {- + -} || word == 0x002D {- - -} then
970+ if length > 1 && isDigit (Text.unsafeIndex array (offset + 1)) then
971+ chompExponentHelp array startOffset (offset + 2) (length - 2)
973+ Left (error "TODO digits after +/-")
976+ Left (error "TODO exponent is messed up")
979+chompExponentHelp :: Text.Array -> Int -> Int -> Int -> Either Error (Int, Int, L.Literal)
980+chompExponentHelp array startOffset offset length =
982+ Right (offset, length, readFloat array startOffset offset)
984+ else if isDigit (Text.unsafeIndex array offset) then
985+ chompExponentHelp array startOffset (offset + 1) (length - 1)
988+ Right (offset, length, readFloat array startOffset offset)
991+chompZero :: Text.Array -> Int -> Int -> Int -> Either Error (Int, Int, L.Literal)
992+chompZero array startOffset offset length =
994+ Right ( offset, length, L.IntNum 0 )
998+ !word = Text.unsafeIndex array offset
1000+ if word == 0x0078 {- x -} then
1001+ chompHex array startOffset (offset + 1) (length - 1)
1003+ else if word == 0x002E {- . -} then
1004+ chompFraction array startOffset (offset + 1) (length - 1)
1006+ else if isDigit word then
1007+ Left (error "TODO zero followed by more numbers")
1010+ Right ( offset, length, L.IntNum 0 )
1013+chompHex :: Text.Array -> Int -> Int -> Int -> Either Error (Int, Int, L.Literal)
1014+chompHex array startOffset offset length =
1015+ if length == 0 then
1016+ Left (error "TODO need hex digits after 0x")
1018+ else if isHex (Text.unsafeIndex array offset) then
1019+ chompHexHelp array startOffset (offset + 1) (length - 1)
1022+ Left (error "TODO need hex digits!")
1025+chompHexHelp :: Text.Array -> Int -> Int -> Int -> Either Error (Int, Int, L.Literal)
1026+chompHexHelp array startOffset offset length =
1027+ if length == 0 then
1028+ Right ( offset, length, readInt array startOffset offset )
1030+ else if isHex (Text.unsafeIndex array offset) then
1031+ chompHexHelp array startOffset (offset + 1) (length - 1)
1034+ Right ( offset, length, readInt array startOffset offset )
1041+{-# INLINE isDigit #-}
1042+isDigit :: Word16 -> Bool
1044+ word <= 0x0039 {- 9 -} && word >= 0x0030 {- 0 -}
1047+{-# INLINE isHex #-}
1048+isHex :: Word16 -> Bool
1050+ word <= 0x0066 {- f -} && (word >= 0x0061 {- a -} || isDigit word || isCapHex word)
1053+{-# INLINE isCapHex #-}
1054+isCapHex :: Word16 -> Bool
1056+ word <= 0x0046 {- F -} && word <= 0x0041 {- A -}
1059+{-# INLINE readInt #-}
1060+readInt :: Text.Array -> Int -> Int -> L.Literal
1061+readInt array startOffset endOffset =
1062+ L.IntNum $ read $ Text.unpack $
1063+ Text.Text array startOffset (endOffset - startOffset)
1066+{-# INLINE readFloat #-}
1067+readFloat :: Text.Array -> Int -> Int -> L.Literal
1068+readFloat array startOffset endOffset =
1069+ L.FloatNum $ read $ Text.unpack $
1070+ Text.Text array startOffset (endOffset - startOffset)