1{-# OPTIONS_GHC -Wall -fno-warn-unused-do-bind #-}
2{-# LANGUAGE BangPatterns, Rank2Types, UnboxedTuples, OverloadedStrings #-}
6 , try, deadend, hint, endOfFile
8 , symbol, underscore, keyword, keywords
9 , lowVar, capVar, infixOp
11 , getContext, pushContext, popContext
12 , getIndent, setIndent
13 , SPos(..), whitespace
14 , docComment, chompUntilDocs
17 , shaderSource, shaderFailure
18 , kernelChunk, ChunkTag(..)
22import Prelude hiding (length)
23import qualified Control.Applicative as Applicative ( Applicative(..), Alternative(..) )
25import qualified Data.ByteString as BS
26import qualified Data.Char as Char
27import Data.Monoid ((<>))
28import qualified Data.Set as Set
29import Data.Text (Text)
30import qualified Data.Text as Text
31import qualified Data.Text.Array as Text
32import qualified Data.Text.Encoding as Text
33import qualified Data.Text.Internal as Text
34import qualified Data.Text.Unsafe as Text
35import qualified Data.Text.Lazy as LT
36import qualified Data.Text.Lazy.Builder as LB
37import Data.Text.Internal.Encoding.Utf16 (chr2)
38import Data.Text.Internal.Unsafe.Char (unsafeChr)
39import GHC.Word (Word8, Word16)
41import qualified AST.Helpers as Help (isSymbol)
42import qualified AST.Literal as L
43import qualified Reporting.Annotation as A
44import qualified Reporting.Error.Syntax as E
45import qualified Reporting.Region as R
46import Reporting.Error.Syntax
47 ( ParseError(..), Problem(..), Theory(..), BadOp(..)
60 -> (a -> State -> ParseError -> b) -- consumed ok
61 -> ( ParseError -> b) -- consumed err
62 -> (a -> State -> ParseError -> b) -- empty ok
63 -> ( ParseError -> b) -- empty err
70 { _array :: !Text.Array
76 , _context :: E.ContextStack
80{-# NOINLINE noError #-}
83 ParseError 0 0 (Theories [] [])
87expect :: Int -> Int -> E.ContextStack -> Theory -> ParseError
88expect row col ctx theory =
89 ParseError row col (Theories ctx [theory])
96run :: Parser a -> Text -> Either (A.Located E.Error) a
101runAt :: Int -> Int -> Parser a -> Text -> Either (A.Located E.Error) a
102runAt sRow sCol parser (Text.Text array offset length) =
103 case _run parser (State array offset length 0 sRow sCol []) Ok Err Ok Err of
107 Err (ParseError row col problem) ->
109 pos = R.Position row col
110 region = R.Region pos pos
111 mkError overallRegion subRegion =
112 Left (A.A overallRegion (E.Parse subRegion problem))
115 BadOp _ ((_, start) : _) ->
116 mkError (R.Region start pos) (Just region)
118 Theories ((_, start) : _) _ ->
119 mkError (R.Region start pos) (Just region)
122 mkError region Nothing
126 = Ok a State ParseError
134try :: Parser a -> Parser a
136 Parser $ \state cok _ eok eerr ->
137 _run parser state cok eerr eok eerr
140shaderFailure :: Int -> Int -> Text -> Parser a
141shaderFailure row col msg =
142 Parser $ \_ _ cerr _ _ ->
143 cerr (ParseError row col (BadShader msg))
146deadend :: [Theory] -> Parser a
148 Parser $ \(State _ _ _ _ row col ctx) _ _ _ eerr ->
149 eerr (ParseError row col (Theories ctx thrys))
152hint :: E.Next -> Parser a -> Parser a
154 Parser $ \state@(State _ _ _ _ row col ctx) cok cerr eok eerr ->
157 eok x s (expect row col ctx (Expecting next))
160 eerr (expect row col ctx (Expecting next))
162 _run parser state cok cerr eok' eerr'
165endOfFile :: Parser ()
167 Parser $ \state@(State _ _ length _ _ _ _) _ _ eok eerr ->
179instance Functor Parser where
181 Parser $ \state cok cerr eok eerr ->
183 cok' x s e = cok (f x) s e
184 eok' x s e = eok (f x) s e
186 _run parser state cok' cerr eok' eerr
193instance Applicative.Applicative Parser where
198instance Applicative.Alternative Parser where
199 empty = allTheOptionsFailed
203oneOf :: [Parser a] -> Parser a
205 foldr oneOfHelp allTheOptionsFailed parsers
208allTheOptionsFailed :: Parser a
210 Parser $ \_ _ _ _ eerr ->
214oneOfHelp :: Parser a -> Parser a -> Parser a
215oneOfHelp parser1 parser2 =
216 Parser $ \state cok cerr eok eerr ->
220 eok2 y s e2 = eok y s (mergeErrors e1 e2)
221 eerr2 e2 = eerr (mergeErrors e1 e2)
223 _run parser2 state cok cerr eok2 eerr2
225 _run parser1 state cok cerr eok eerr1
228mergeErrors :: ParseError -> ParseError -> ParseError
229mergeErrors e1@(ParseError r1 c1 p1) e2@(ParseError r2 c2 p2) =
230 case compare r1 r2 of
234 case compare c1 c2 of
239 (Theories _ [], Theories _ _) ->
242 (Theories _ _, Theories _ []) ->
245 (Theories ctx ts1, Theories _ ts2) ->
246 ParseError r1 c1 (Theories ctx (ts1 ++ ts2))
259instance Monad Parser where
261 Parser $ \state _ _ eok _ ->
262 eok value state noError
264 parser >>= callback =
265 Parser $ \state cok cerr eok eerr ->
269 eok2 y s2 e2 = cok y s2 (mergeErrors e1 e2)
270 eerr2 e2 = cerr (mergeErrors e1 e2)
272 _run (callback x) s1 cok cerr eok2 eerr2
276 eok2 y s2 e2 = eok y s2 (mergeErrors e1 e2)
277 eerr2 e2 = eerr (mergeErrors e1 e2)
279 _run (callback x) s1 cok cerr eok2 eerr2
281 _run parser state cok1 cerr eok1 eerr
288symbol :: Text -> Parser ()
289symbol sym@(Text.Text tArray tOffset tLen) =
290 Parser $ \(State array offset length indent row col ctx) cok _ _ eerr ->
291 if tLen <= length && Text.equal tArray tOffset array offset tLen then
293 (# newRow, newCol #) =
294 moveCursor tArray tOffset tLen row col
297 State array (offset + tLen) (length - tLen) indent newRow newCol ctx
299 cok () newState noError
302 eerr (expect row col ctx (Symbol sym))
305moveCursor :: Text.Array -> Int -> Int -> Int -> Int -> (# Int, Int #)
306moveCursor array offset length row col =
312 !word = Text.unsafeIndex array offset
314 if word == 0x000A {- \n -} then
315 moveCursor array (offset + 1) (length - 1) (row + 1) 1
317 else if word < 0xD800 || word > 0xDBFF then
318 moveCursor array (offset + 1) (length - 1) row (col + 1)
321 moveCursor array (offset + 2) (length - 2) row (col + 1)
324underscore :: Parser ()
326 Parser $ \(State array offset length indent row col ctx) cok cerr _ eerr ->
327 if length == 0 || Text.unsafeIndex array offset /= 0x005F {- _ -} then
330 else if length >= 2 && isInnerVarChar (peekChar array (offset + 1)) then
331 cerr (ParseError row (col + 1) (BadUnderscore (peekChar array (offset + 1))))
336 State array (offset + 1) (length - 1) indent row (col + 1) ctx
338 cok () newState noError
345keyword :: Text -> Parser ()
346keyword kwd@(Text.Text tArray tOffset tLen) =
347 Parser $ \(State array offset length indent row col ctx) cok _ _ eerr ->
348 if tLen <= length && Text.equal tArray tOffset array offset tLen then
350 if isInnerVarChar (peekChar array (offset + tLen)) then
351 eerr (expect row col ctx (Keyword kwd))
355 (# newRow, newCol #) =
356 moveCursor tArray tOffset tLen row col
359 State array (offset + tLen) (length - tLen) indent newRow newCol ctx
361 cok () newState noError
364 eerr (expect row col ctx (Keyword kwd))
367keywords :: Set.Set Text
370 [ "if", "then", "else"
375 , "import", "exposing"
385lowVar :: Parser Text.Text
387 varPrim LowVar Char.isLower
390capVar :: Parser Text.Text
392 varPrim CapVar Char.isUpper
395{-# INLINE varPrim #-}
396varPrim :: Theory -> (Char -> Bool) -> Parser Text.Text
397varPrim theory isGoodFirstChar =
398 Parser $ \(State array offset length indent row col ctx) cok _ _ eerr ->
400 eerr (expect row col ctx theory)
404 (Text.Iter char size) = peek array offset
406 if isGoodFirstChar char then
408 (# newOffset, newLength, newCol #) =
409 varPrimHelp array (offset + size) (length - size) (col + 1)
412 copyText array offset (newOffset - offset)
414 if Set.member copiedText keywords then
415 eerr (expect row newCol ctx theory)
417 cok copiedText (State array newOffset newLength indent row newCol ctx) noError
420 eerr (expect row col ctx theory)
423{-# INLINE copyText #-}
424copyText :: Text.Array -> Int -> Int -> Text.Text
425copyText array offset size =
428 do mutableArray <- Text.new size
429 Text.copyI mutableArray 0 array offset size
432 Text.Text (Text.run makeArray) 0 size
436peek :: Text.Array -> Int -> Text.Iter
439 !word = Text.unsafeIndex array offset
441 if word < 0xD800 || word > 0xDBFF then
442 Text.Iter (unsafeChr word) 1
444 Text.Iter (chr2 word (Text.unsafeIndex array (offset + 1))) 2
447{-# INLINE peekChar #-}
448peekChar :: Text.Array -> Int -> Char
449peekChar array offset =
451 !word = Text.unsafeIndex array offset
453 if word < 0xD800 || word > 0xDBFF then
456 chr2 word (Text.unsafeIndex array (offset + 1))
459varPrimHelp :: Text.Array -> Int -> Int -> Int -> (# Int, Int, Int #)
460varPrimHelp array offset length col =
462 (# offset, length, col #)
466 (Text.Iter char size) = peek array offset -- TODO look for latin chars directly?
468 if isInnerVarChar char then
469 varPrimHelp array (offset + size) (length - size) (col + 1)
472 (# offset, length, col #)
475{-# INLINE isInnerVarChar #-}
476isInnerVarChar :: Char -> Bool
478 Char.isAlphaNum char || char == '_'
485infixOp :: Parser Text
487 Parser $ \(State array offset length indent row col ctx) cok cerr _ eerr ->
489 eerr (expect row col ctx InfixOp)
493 (Text.Iter char size) = peek array offset
495 if not (Help.isSymbol char) then
496 eerr (expect row col ctx InfixOp)
498 case infixOpHelp array (offset + size) (length - size) row (col + 1) of
502 Right ( newOffset, newLength, newCol ) ->
503 case copyText array offset (newOffset - offset) of
504 "." -> cerr (ParseError row col (BadOp Dot ctx))
505 "|" -> cerr (ParseError row col (BadOp Pipe ctx))
506 "->" -> cerr (ParseError row col (BadOp Arrow ctx))
507 "=" -> cerr (ParseError row col (BadOp Equals ctx))
508 ":" -> cerr (ParseError row col (BadOp HasType ctx))
509 op -> cok op (State array newOffset newLength indent row newCol ctx) noError
512infixOpHelp :: Text.Array -> Int -> Int -> Int -> Int -> Either ParseError (Int, Int, Int)
513infixOpHelp array offset length row col =
515 Right ( offset, length, col )
519 (Text.Iter char size) = peek array offset
521 if Help.isSymbol char then
522 infixOpHelp array (offset + size) (length - size) row (col + 1)
524 Right ( offset, length, col )
531getPosition :: Parser R.Position
533 Parser $ \state@(State _ _ _ _ row col _) _ _ eok _ ->
534 eok (R.Position row col) state noError
537getIndent :: Parser Int
539 Parser $ \state@(State _ _ _ indent _ _ _) _ _ eok _ ->
540 eok indent state noError
545 Parser $ \state@(State _ _ _ _ _ col _) _ _ eok _ ->
546 eok col state noError
549getContext :: Parser E.ContextStack
551 Parser $ \state@(State _ _ _ _ _ _ ctx) _ _ eok _ ->
552 eok ctx state noError
555pushContext :: R.Position -> E.Context -> Parser ()
557 Parser $ \state@(State _ _ _ _ _ _ context) _ _ eok _ ->
558 eok () (state { _context = (ctx, pos) : context }) noError
561popContext :: a -> Parser a
563 Parser $ \state@(State _ _ _ _ _ _ context) _ _ eok _ ->
564 eok value (state { _context = tail context }) noError
567setIndent :: Int -> Parser ()
569 Parser $ \state _ _ eok _ ->
570 eok () (state { _indent = indent }) noError
581whitespace :: Parser SPos
583 Parser $ \(State array offset length indent row col ctx) cok cerr _ _ ->
584 case eatSpaces array offset length row col of
588 Right (newOffset, newLength, newRow, newCol) ->
590 (SPos (R.Position newRow newCol))
591 (State array newOffset newLength indent newRow newCol ctx)
595eatSpaces :: Text.Array -> Int -> Int -> Int -> Int -> Either ParseError ( Int, Int, Int, Int )
596eatSpaces array offset length row col =
598 Right ( offset, length, row, col )
601 case Text.unsafeIndex array offset of
603 eatSpaces array (offset + 1) (length - 1) row (col + 1)
606 eatSpaces array (offset + 1) (length - 1) (row + 1) 1
609 eatMultiComment array offset length row col
612 eatLineComment array offset length row col
615 eatSpaces array (offset + 1) (length - 1) row col
618 Left (ParseError row col Tab)
621 Right ( offset, length, row, col )
628eatLineComment :: Text.Array -> Int -> Int -> Int -> Int -> Either ParseError ( Int, Int, Int, Int )
629eatLineComment array offset length row col =
631 Right ( offset, length, row, col )
634 case Text.unsafeIndex array (offset + 1) of
636 eatLineCommentHelp array (offset + 2) (length - 2) row (col + 2)
639 Right ( offset, length, row, col )
642eatLineCommentHelp :: Text.Array -> Int -> Int -> Int -> Int -> Either ParseError ( Int, Int, Int, Int )
643eatLineCommentHelp array offset length row col =
645 Right ( offset, length, row, col )
649 !word = Text.unsafeIndex array offset
651 if word == 0x000A {- \n -} then
652 eatSpaces array (offset + 1) (length - 1) (row + 1) 1
654 else if word < 0xD800 || word > 0xDBFF then
655 eatLineCommentHelp array (offset + 1) (length - 1) row (col + 1)
658 eatLineCommentHelp array (offset + 2) (length - 2) row (col + 1)
665eatMultiComment :: Text.Array -> Int -> Int -> Int -> Int -> Either ParseError ( Int, Int, Int, Int )
666eatMultiComment array offset length row col =
668 Right ( offset, length, row, col )
672 !yesDash = Text.unsafeIndex array (offset + 1) == 0x002D {- - -}
673 !noBar = Text.unsafeIndex array (offset + 2) /= 0x007C {- | -}
675 if yesDash && noBar then
676 do (newOffset, newLength, newRow, newCol) <-
677 eatMultiCommentHelp array (offset + 2) (length - 2) row (col + 2) 1
678 eatSpaces array newOffset newLength newRow newCol
681 Right ( offset, length, row, col )
684eatMultiCommentHelp :: Text.Array -> Int -> Int -> Int -> Int -> Int -> Either ParseError ( Int, Int, Int, Int )
685eatMultiCommentHelp array offset length row col openComments =
687 Left (ParseError row col EndOfFile_Comment)
691 !word = Text.unsafeIndex array offset
693 if word == 0x000A {- \n -} then
695 eatMultiCommentHelp array (offset + 1) (length - 1) (row + 1) 1 openComments
697 else if word == 0x002D {- - -} && length > 1 && Text.unsafeIndex array (offset + 1) == 0x007D {- } -} then
699 if openComments == 1 then
700 Right ( offset + 2, length - 2, row, col + 2 )
702 eatMultiCommentHelp array (offset + 2) (length - 2) row (col + 2) (openComments - 1)
704 else if word == 0x007B {- { -} && length > 1 && Text.unsafeIndex array (offset + 1) == 0x002D {- - -} then
706 eatMultiCommentHelp array (offset + 2) (length - 2) row (col + 2) (openComments + 1)
708 else if word < 0xD800 || word > 0xDBFF then
710 eatMultiCommentHelp array (offset + 1) (length - 1) row (col + 1) openComments
714 eatMultiCommentHelp array (offset + 2) (length - 2) row (col + 1) openComments
718-- DOCUMENTATION COMMENT
721docComment :: Parser Text
724 Parser $ \(State array offset length indent row col ctx) cok cerr _ _ ->
725 case eatMultiCommentHelp array offset length row col 1 of
729 Right (newOffset, newLength, newRow, newCol) ->
731 (copyText array offset (newOffset - offset))
732 (State array newOffset newLength indent newRow newCol ctx)
736chompUntilDocs :: Parser Bool
738 Parser $ \(State array offset length indent row col ctx) cok _ _ _ ->
740 (# isStart, newOffset, newLength, newRow, newCol #) =
741 eatDocs array offset length row col
744 State array newOffset newLength indent newRow newCol ctx
746 cok isStart newState noError
749eatDocs :: Text.Array -> Int -> Int -> Int -> Int -> (# Bool, Int, Int, Int, Int #)
750eatDocs array offset length row col =
752 (# False, offset, length, row, col #)
754 else if isDocsStart array offset length then
755 (# True, offset + 5, length - 5, row, col + 5 #)
759 !word = Text.unsafeIndex array offset
761 if word == 0x000A {- \n -} then
762 eatDocs array (offset + 1) (length - 1) (row + 1) 1
764 else if word < 0xD800 || word > 0xDBFF then
765 eatDocs array (offset + 1) (length - 1) row (col + 1)
768 eatDocs array (offset + 2) (length - 2) row (col + 1)
771isDocsStart :: Text.Array -> Int -> Int -> Bool
772isDocsStart array offset length =
774 && Text.unsafeIndex array offset == 0x0040 {- @ -}
775 && Text.unsafeIndex array (offset + 1) == 0x0064 {- d -}
776 && Text.unsafeIndex array (offset + 2) == 0x006F {- o -}
777 && Text.unsafeIndex array (offset + 3) == 0x0063 {- c -}
778 && Text.unsafeIndex array (offset + 4) == 0x0073 {- s -}
785string :: Parser Text.Text
787 Parser $ \(State array offset length indent row col ctx) cok cerr _ eerr ->
793 !word = Text.unsafeIndex array offset
795 if word /= 0x0022 {- " -} then
801 if length >= 3 && isQuote array (offset + 1) && isQuote array (offset + 2) then
802 multiString array (offset + 3) (length - 3) row (col + 3) (offset + 3) mempty
804 singleString array (offset + 1) (length - 1) row (col + 1) (offset + 1) mempty
810 Right ( newOffset, newLength, newCol, builder ) ->
812 (LT.toStrict (LB.toLazyText builder))
813 (State array newOffset newLength indent row newCol ctx)
817{-# INLINE isQuote #-}
818isQuote :: Text.Array -> Int -> Bool
819isQuote array offset =
820 Text.unsafeIndex array offset == 0x0022 {- " -}
827singleString :: Text.Array -> Int -> Int -> Int -> Int -> Int -> LB.Builder -> Either ParseError ( Int, Int, Int, LB.Builder )
828singleString array offset length row col initialOffset builder =
830 Left (ParseError row col EndOfFile_String)
834 !word = Text.unsafeIndex array offset
836 if word == 0x0022 {- " -} then
839 mappend builder $ LB.fromText $
840 Text.Text array initialOffset (offset - initialOffset)
842 Right ( offset + 1, length - 1, col + 1, finalBuilder )
844 else if word == 0x000A {- \n -} then
845 Left (ParseError row col NewLineInString)
847 else if word == 0x0027 {- ' -} then
850 !newOffset = offset + 1
851 chunk = Text.Text array initialOffset (offset - initialOffset)
852 newBuilder = builder <> LB.fromText chunk <> LB.fromText "\\'"
854 singleString array newOffset (length - 1) row (col + 1) newOffset newBuilder
856 else if word == 0x005C {- \ -} then
857 case eatEscape array (offset + 1) (length - 1) row (col + 1) EndOfFile_String of
862 singleString array (offset + size) (length - size) row (col + size) initialOffset builder
864 else if word < 0xD800 || word > 0xDBFF then
865 singleString array (offset + 1) (length - 1) row (col + 1) initialOffset builder
868 singleString array (offset + 2) (length - 2) row (col + 1) initialOffset builder
871eatEscape :: Text.Array -> Int -> Int -> Int -> Int -> Problem -> Either ParseError Int
872eatEscape array offset length row col problem =
874 Left (ParseError row col problem)
877 case Text.unsafeIndex array offset of
878 0x0061 {- a -} -> Right 2
879 0x0062 {- b -} -> Right 2
880 0x0066 {- f -} -> Right 2
881 0x006E {- n -} -> Right 2
882 0x0072 {- r -} -> Right 2
883 0x0074 {- t -} -> Right 2
884 0x0076 {- v -} -> Right 2
885 0x0022 {- " -} -> Right 2
886 0x005C {- \ -} -> Right 2
887 0x0027 {- ' -} -> Right 2
888 0x0075 {- u -} | length >= 5 && fourHex array offset -> Right 6
890 Left (ParseError row col BadEscape)
893fourHex :: Text.Array -> Int -> Bool
894fourHex array offset =
895 isHex (Text.unsafeIndex array (offset + 1))
896 && isHex (Text.unsafeIndex array (offset + 2))
897 && isHex (Text.unsafeIndex array (offset + 3))
898 && isHex (Text.unsafeIndex array (offset + 4))
905multiString :: Text.Array -> Int -> Int -> Int -> Int -> Int -> LB.Builder -> Either ParseError ( Int, Int, Int, LB.Builder )
906multiString array offset length row col initialOffset builder =
908 Left (ParseError row col EndOfFile_MultiString)
912 !word = Text.unsafeIndex array offset
914 if word == 0x0022 {- " -} && isQuote array (offset + 1) && isQuote array (offset + 2) then
918 mappend builder $ LB.fromText $
919 Text.Text array initialOffset (offset - initialOffset)
921 Right ( offset + 3, length - 3, col + 3, finalBuilder )
923 else if word == 0x0027 {- ' -} then
926 !newOffset = offset + 1
927 chunk = Text.Text array initialOffset (offset - initialOffset)
928 newBuilder = builder <> LB.fromText chunk <> LB.fromText "\\'"
930 multiString array newOffset (length - 1) row (col + 1) newOffset newBuilder
932 else if word == 0x000A {- \n -} then
935 !newOffset = offset + 1
936 chunk = Text.Text array initialOffset (offset - initialOffset)
937 newBuilder = builder <> LB.fromText chunk <> LB.fromText "\\n"
939 multiString array newOffset (length - 1) (row + 1) 1 newOffset newBuilder
941 else if word == 0x005C {- \ -} then
943 case eatEscape array (offset + 1) (length - 1) row (col + 1) EndOfFile_MultiString of
948 multiString array (offset + size) (length - size) row (col + size) initialOffset builder
950 else if word < 0xD800 || word > 0xDBFF then
951 multiString array (offset + 1) (length - 1) row (col + 1) initialOffset builder
954 multiString array (offset + 2) (length - 2) row (col + 1) initialOffset builder
961character :: Parser Text
963 Parser $ \(State array offset length indent row col ctx) cok cerr _ eerr ->
968 if Text.unsafeIndex array offset /= 0x0027 {- ' -} then
971 else if length < 3 then
972 cerr (ParseError row col BadChar)
975 case characterHelp array (offset + 1) (length - 1) row (col + 1) of
979 Right (endCol, size) ->
981 !newOffset = offset + size + 1
982 !newLength = length - size - 1
984 if newLength == 0 || Text.unsafeIndex array newOffset /= 0x0027 {- ' -} then
985 cerr (ParseError row col BadChar)
989 (copyText array (offset + 1) size)
990 (State array (newOffset + 1) (newLength - 1) indent row endCol ctx)
994characterHelp :: Text.Array -> Int -> Int -> Int -> Int -> Either ParseError ( Int, Int )
995characterHelp array offset length row col =
997 !word = Text.unsafeIndex array offset
999 if word == 0x0027 {- ' -} || word == 0x000A {- \n -} then
1000 Left (ParseError row col BadChar)
1002 else if word == 0x005C {- \ -} then
1003 do n <- eatEscape array (offset + 1) (length - 1) row (col + 1) BadChar
1004 return (col + n + 2, n)
1006 else if word < 0xD800 || word > 0xDBFF then
1009 else if length > 2 then
1013 Left (ParseError row col BadChar)
1022 Parser $ \(State array offset length indent row col ctx) cok _ _ eerr ->
1024 eerr (expect row col ctx Digit)
1028 !word = Text.unsafeIndex array offset
1030 if isDigit word then
1032 (fromIntegral (word - 0x0030 {- 0 -}))
1033 (State array (offset + 1) (length - 1) indent row (col + 1) ctx)
1036 eerr (expect row col ctx Digit)
1043number :: Parser L.Literal
1045 Parser $ \(State array offset length indent row col ctx) cok cerr _ eerr ->
1051 !word = Text.unsafeIndex array offset
1053 if not (isDigit word) then
1059 if word == 0x0030 {- 0 -} then
1060 chompZero array offset (offset + 1) (length - 1)
1062 chompInt array offset (offset + 1) (length - 1)
1064 case chompResults of
1065 Left (newOffset, problem) ->
1066 cerr (ParseError row (col + (newOffset - offset)) problem)
1068 Right (newOffset, newLength, literal) ->
1069 if isDirtyEnd array newOffset newLength then
1070 cerr (ParseError row (col + (newOffset - offset)) BadNumberEnd)
1075 (State array newOffset newLength indent row (col + (newOffset - offset)) ctx)
1079isDirtyEnd :: Text.Array -> Int -> Int -> Bool
1080isDirtyEnd array offset length =
1086 !char = peekChar array offset
1088 Char.isAlpha char || char == '_'
1091chompInt :: Text.Array -> Int -> Int -> Int -> Either (Int, Problem) (Int, Int, L.Literal)
1092chompInt array startOffset offset length =
1095 Right ( offset, length, readInt array startOffset offset )
1100 !word = Text.unsafeIndex array offset
1102 if isDigit word then
1103 chompInt array startOffset (offset + 1) (length - 1)
1105 else if word == 0x002E {- . -} then
1106 chompFraction array startOffset (offset + 1) (length - 1)
1108 else if word == 0x0065 {- e -} || word == 0x0045 {- E -} then
1109 chompExponent array startOffset (offset + 1) (length - 1)
1112 Right ( offset, length, readInt array startOffset offset )
1115chompFraction :: Text.Array -> Int -> Int -> Int -> Either (Int, Problem) (Int, Int, L.Literal)
1116chompFraction array startOffset offset length =
1118 Left (offset, BadNumberDot)
1120 else if isDigit (Text.unsafeIndex array offset) then
1121 chompFractionHelp array startOffset (offset + 1) (length - 1)
1124 Left (offset, BadNumberDot)
1127chompFractionHelp :: Text.Array -> Int -> Int -> Int -> Either (Int, Problem) (Int, Int, L.Literal)
1128chompFractionHelp array startOffset offset length =
1130 Right (offset, length, readFloat array startOffset offset)
1134 !word = Text.unsafeIndex array offset
1136 if isDigit word then
1137 chompFractionHelp array startOffset (offset + 1) (length - 1)
1139 else if word == 0x0065 {- e -} || word == 0x0045 {- E -} then
1140 chompExponent array startOffset (offset + 1) (length - 1)
1143 Right (offset, length, readFloat array startOffset offset)
1146chompExponent :: Text.Array -> Int -> Int -> Int -> Either (Int, Problem) (Int, Int, L.Literal)
1147chompExponent array startOffset offset length =
1149 Right (offset, length, readFloat array startOffset offset)
1153 !word = Text.unsafeIndex array offset
1155 if isDigit word then
1156 chompExponentHelp array startOffset (offset + 1) (length - 1)
1158 else if word == 0x002B {- + -} || word == 0x002D {- - -} then
1160 if length > 1 && isDigit (Text.unsafeIndex array (offset + 1)) then
1161 chompExponentHelp array startOffset (offset + 2) (length - 2)
1163 Left (offset, BadNumberExp)
1166 Left (offset, BadNumberExp)
1169chompExponentHelp :: Text.Array -> Int -> Int -> Int -> Either (Int, Problem) (Int, Int, L.Literal)
1170chompExponentHelp array startOffset offset length =
1172 Right (offset, length, readFloat array startOffset offset)
1174 else if isDigit (Text.unsafeIndex array offset) then
1175 chompExponentHelp array startOffset (offset + 1) (length - 1)
1178 Right (offset, length, readFloat array startOffset offset)
1181chompZero :: Text.Array -> Int -> Int -> Int -> Either (Int, Problem) (Int, Int, L.Literal)
1182chompZero array startOffset offset length =
1184 Right ( offset, length, L.IntNum 0 )
1188 !word = Text.unsafeIndex array offset
1190 if word == 0x0078 {- x -} then
1191 chompHex array startOffset (offset + 1) (length - 1)
1193 else if word == 0x002E {- . -} then
1194 chompFraction array startOffset (offset + 1) (length - 1)
1196 else if isDigit word then
1197 Left (offset, BadNumberZero)
1200 Right ( offset, length, L.IntNum 0 )
1203chompHex :: Text.Array -> Int -> Int -> Int -> Either (Int, Problem) (Int, Int, L.Literal)
1204chompHex array startOffset offset length =
1206 Left (offset, BadNumberHex)
1208 else if isHex (Text.unsafeIndex array offset) then
1209 chompHexHelp array startOffset (offset + 1) (length - 1)
1212 Left (offset, BadNumberHex)
1215chompHexHelp :: Text.Array -> Int -> Int -> Int -> Either (Int, Problem) (Int, Int, L.Literal)
1216chompHexHelp array startOffset offset length =
1218 Right ( offset, length, readInt array startOffset offset )
1220 else if isHex (Text.unsafeIndex array offset) then
1221 chompHexHelp array startOffset (offset + 1) (length - 1)
1224 Right ( offset, length, readInt array startOffset offset )
1231{-# INLINE isDigit #-}
1232isDigit :: Word16 -> Bool
1234 word <= 0x0039 {- 9 -} && word >= 0x0030 {- 0 -}
1238isHex :: Word16 -> Bool
1240 word <= 0x0066 {- f -} && (word >= 0x0061 {- a -} || isDigit word || isCapHex word)
1243{-# INLINE isCapHex #-}
1244isCapHex :: Word16 -> Bool
1246 0x0041 {- A -} <= word && word <= 0x0046 {- F -}
1249{-# INLINE readInt #-}
1250readInt :: Text.Array -> Int -> Int -> L.Literal
1251readInt array startOffset endOffset =
1252 L.IntNum $ read $ Text.unpack $
1253 Text.Text array startOffset (endOffset - startOffset)
1256{-# INLINE readFloat #-}
1257readFloat :: Text.Array -> Int -> Int -> L.Literal
1258readFloat array startOffset endOffset =
1259 L.FloatNum $ read $ Text.unpack $
1260 Text.Text array startOffset (endOffset - startOffset)
1267shaderSource :: Parser Text
1270 Parser $ \(State array offset length indent row col ctx) cok cerr _ _ ->
1271 case eatShader array offset length row col of
1273 cerr (ParseError row col EndOfFile_Shader)
1275 Just ( shaderEndOffset, newRow, newCol ) ->
1277 !size = shaderEndOffset - offset
1279 State array (shaderEndOffset + 2) (length - size - 2) indent newRow newCol ctx
1281 cok (copyText array offset size) newState noError
1284eatShader :: Text.Array -> Int -> Int -> Int -> Int -> Maybe (Int, Int, Int)
1285eatShader array offset length row col =
1291 !word = Text.unsafeIndex array offset
1293 if word == 0x007C {- | -} && Text.unsafeIndex array (offset + 1) == 0x005D {- ] -} then
1294 Just ( offset, row, col + 2 )
1296 else if word == 0x000A {- \n -} then
1297 eatShader array (offset + 1) (length - 1) (row + 1) 1
1299 else if word < 0xD800 || word > 0xDBFF then
1300 eatShader array (offset + 1) (length - 1) row (col + 1)
1303 eatShader array (offset + 2) (length - 2) row (col + 1)
1310data ChunkTag = KernelEnum Word8 | KernelImport
1313kernelChunk :: Parser (BS.ByteString, Maybe (ChunkTag, Text))
1315 Parser $ \(State array offset length indent row col ctx) cok _ _ _ ->
1317 (# maybeChunkTag, newOffset, newLength, newRow, newCol #) =
1318 kernelChunkHelp array offset length row col
1321 Text.encodeUtf8 (Text.Text array offset (newOffset - offset))
1323 case maybeChunkTag of
1327 State array newOffset newLength indent newRow newCol ctx
1329 cok (javascript, Nothing) newState noError
1333 (# newerOffset, newerLength, newerCol #) =
1334 varPrimHelp array newOffset newLength newCol
1337 State array newerOffset newerLength indent newRow newerCol ctx
1340 Text.Text array newOffset (newerOffset - newOffset)
1342 cok (javascript, Just (tag, kernelSymbol)) newState noError
1345kernelChunkHelp :: Text.Array -> Int -> Int -> Int -> Int -> (# Maybe ChunkTag, Int, Int, Int, Int #)
1346kernelChunkHelp array offset length row col =
1348 (# Nothing, offset, length, row, col #)
1352 !word = Text.unsafeIndex array offset
1354 if word == 0x005F {- _ -} && length > 3 && Text.unsafeIndex array (offset + 1) == 0x005F {- _ -} then
1355 (# Just (toChunkTag (Text.unsafeIndex array (offset + 2))), offset, length, row, col #)
1357 else if word == 0x000A {- \n -} then
1358 kernelChunkHelp array (offset + 1) (length - 1) (row + 1) 1
1360 else if word < 0xD800 || word > 0xDBFF then
1361 kernelChunkHelp array (offset + 1) (length - 1) row (col + 1)
1364 kernelChunkHelp array (offset + 2) (length - 2) row (col + 1)
1367toChunkTag :: Word16 -> ChunkTag
1369 if isDigit word then
1370 KernelEnum (fromIntegral (word - 0x0030 {- 0 -}))
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list