gigaparsec 0.2.5.0 → 0.2.5.1
raw patch · 8 files changed
+197/−46 lines, 8 filesPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
API changes (from Hackage documentation)
+ Text.Gigaparsec.Token.Errors: filterCharNonAscii :: ErrorConfig -> VanillaFilterConfig Char
+ Text.Gigaparsec.Token.Errors: filterCharNonLatin1 :: ErrorConfig -> VanillaFilterConfig Char
+ Text.Gigaparsec.Token.Errors: filterEscapeCharNumericSequenceIllegal :: ErrorConfig -> Char -> Int -> SpecializedFilterConfig Integer
+ Text.Gigaparsec.Token.Errors: filterEscapeCharRequiresExactDigits :: ErrorConfig -> Int -> NonEmpty Word -> SpecializedFilterConfig Word
+ Text.Gigaparsec.Token.Errors: filterIntegerOutOfBounds :: ErrorConfig -> Integer -> Integer -> Int -> FilterConfig Integer
+ Text.Gigaparsec.Token.Errors: filterNameIllFormedIdentifier :: ErrorConfig -> FilterConfig String
+ Text.Gigaparsec.Token.Errors: filterNameIllFormedOperator :: ErrorConfig -> FilterConfig String
+ Text.Gigaparsec.Token.Errors: filterStringNonAscii :: ErrorConfig -> SpecializedFilterConfig String
+ Text.Gigaparsec.Token.Errors: filterStringNonLatin1 :: ErrorConfig -> SpecializedFilterConfig String
+ Text.Gigaparsec.Token.Errors: labelCharAscii :: ErrorConfig -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelCharAsciiEnd :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelCharLatin1 :: ErrorConfig -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelCharLatin1End :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelCharUnicode :: ErrorConfig -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelCharUnicodeEnd :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelEscapeEnd :: ErrorConfig -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelEscapeNumeric :: ErrorConfig -> Int -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelEscapeNumericEnd :: ErrorConfig -> Char -> Int -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelEscapeSequence :: ErrorConfig -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelGraphicCharacter :: ErrorConfig -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerBinaryEnd :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerDecimalEnd :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerHexadecimalEnd :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerNumberEnd :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerOctalEnd :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerSignedBinary :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerSignedDecimal :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerSignedHexadecimal :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerSignedNumber :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerSignedOctal :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerUnsignedBinary :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerUnsignedDecimal :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerUnsignedHexadecimal :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerUnsignedNumber :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelIntegerUnsignedOctal :: ErrorConfig -> Maybe Bits -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelNameIdentifier :: ErrorConfig -> String
+ Text.Gigaparsec.Token.Errors: labelNameOperator :: ErrorConfig -> String
+ Text.Gigaparsec.Token.Errors: labelNumericBreakChar :: ErrorConfig -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelSpaceEndOfLineComment :: ErrorConfig -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelSpaceEndOfMultiComment :: ErrorConfig -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelStringAscii :: ErrorConfig -> Bool -> Bool -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelStringAsciiEnd :: ErrorConfig -> Bool -> Bool -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelStringCharacter :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelStringEscapeEmpty :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelStringEscapeGap :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelStringEscapeGapEnd :: ErrorConfig -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelStringLatin1 :: ErrorConfig -> Bool -> Bool -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelStringLatin1End :: ErrorConfig -> Bool -> Bool -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelStringUnicode :: ErrorConfig -> Bool -> Bool -> LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelStringUnicodeEnd :: ErrorConfig -> Bool -> Bool -> LabelConfig
+ Text.Gigaparsec.Token.Errors: labelSymbol :: ErrorConfig -> Map String LabelWithExplainConfig
+ Text.Gigaparsec.Token.Errors: labelSymbolEndOfKeyword :: ErrorConfig -> String -> String
+ Text.Gigaparsec.Token.Errors: labelSymbolEndOfOperator :: ErrorConfig -> String -> String
+ Text.Gigaparsec.Token.Errors: unexpectedNameIllegalIdentifier :: ErrorConfig -> String -> String
+ Text.Gigaparsec.Token.Errors: unexpectedNameIllegalOperator :: ErrorConfig -> String -> String
+ Text.Gigaparsec.Token.Errors: verifiedCharBadCharsUsedInLiteral :: ErrorConfig -> VerifiedBadChars
+ Text.Gigaparsec.Token.Errors: verifiedStringBadCharsUsedInLiteral :: ErrorConfig -> VerifiedBadChars
Files
- CHANGELOG.md +3/−0
- gigaparsec.cabal +1/−1
- src/Text/Gigaparsec.hs +126/−14
- src/Text/Gigaparsec/Combinator.hs +1/−1
- src/Text/Gigaparsec/Errors/Combinator.hs +4/−1
- src/Text/Gigaparsec/Internal.hs +30/−2
- src/Text/Gigaparsec/Token/Errors.hs +26/−27
- test/Text/Gigaparsec/ErrorsTests.hs +6/−0
CHANGELOG.md view
@@ -1,5 +1,8 @@ # Revision history for gigaparsec +## 0.2.5.1 -- 2024-02-07+* Fixed bug where hints can be revived by the `hide` combinator.+ ## 0.2.5.0 -- 2024-02-04 * Supported `Text.Gigaparsec.Errors.TokenExtractors`, which allows for recipes for token extraction during error message creation.
gigaparsec.cabal view
@@ -20,7 +20,7 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 0.2.5.0+version: 0.2.5.1 -- A short (one-line) description of the package. synopsis:
src/Text/Gigaparsec.hs view
@@ -10,8 +10,6 @@ This object contains the core combinators and parser type: all parsers will require something from within! -TODO: what is inside it?- @since 0.1.0.0 -} module Text.Gigaparsec (@@ -110,7 +108,7 @@ This is chosen instead of @Either@ to be more specific about the naming. -} type Result :: * -> * -> *-data Result e a = Success a | Failure e deriving stock (Show, Eq, Generic)+data Result e a = Success a | Failure e deriving stock (Show, Eq, Generic) -- TODO: monad? {-| A fold for the 'Result' type.@@ -249,10 +247,8 @@ part of some larger valid identifier (i.e. the keyword \"if\" should not parse successfully given \"ifp\"). This can be accomplished as follows: -@-keyword :: String -> Parsec ()-keyword kw = atomic $ string kw *> notFollowedBy letterOrDigit-@+> keyword :: String -> Parsec ()+> keyword kw = atomic $ string kw *> notFollowedBy letterOrDigit @since 0.1.0.0 -}@@ -264,7 +260,7 @@ (\_ _ -> ok () st) -- eof is usually `notFollowedBy item`, but this requires annoying cyclic dependencies on Char-{- This parser only succeeds at the end of the input.+{-| This parser only succeeds at the end of the input. Equivalent to `notFollowedBy(item)`. @@ -293,26 +289,111 @@ unit :: Parsec () unit = pure () +{-|+This combinator, pronounced "zip", first parses this parser then parses @q@: if both succeed the result of this+parser is paired with the result of @q@.++First, this parser is ran, yielding @x@ on success, then @q@ is ran, yielding @y@ on success. If both+are successful then @(x, y)@ is returned. If either fail then the entire combinator fails.++==== __Examples__+>>> p = char 'a' <~> char 'b'+>>> parse p "ab"+Success ('a', 'b')+>>> parse p "b"+Failure ..+>>> parse p "a"+Failure ..+-} infixl 4 <~> (<~>) :: Parsec a -> Parsec b -> Parsec (a, b) (<~>) = liftA2 (,) +{-|+This combinator, pronounced "as", replaces the result of this parser, ignoring the old result.++Similar to @(<$>)@, except the old result of this parser is not required to+compute the new result. This is useful when the result is a constant value (or function!).+Functionally the same as @p *> pure x@ or @const x <$> p@.++/In @parsley@, this combinator is known as @#>@ or @as@/.++==== __Examples__+>>> parse (string "true" $> true) "true"+Success true+-} infixl 4 $> ($>) :: Parsec a -> b -> Parsec b ($>) = flip (<$) +{-|+This combinator, pronounced "cons", first parses this parser then parses @ps@: if both succeed the result of this+parser is prepended onto the result of @ps@.++First, this parser is ran, yielding @x@ on success, then @ps@ is ran, yielding @xs@ on success. If both+are successful then @x : xs@ is returned. If either fail then the entire combinator fails.++==== __Examples__+> some p = p <:> many(p)+-} infixl 4 <:> (<:>) :: Parsec a -> Parsec [a] -> Parsec [a] (<:>) = liftA2 (:) infixl 3 <+>+{-|+This combinator, pronounced "sum", wraps this parser's result in @Left@ if it succeeds, and parses @q@ if it failed __without__ consuming input,+wrapping the result in @Right@.++If this parser is successful, then its result is wrapped up using @Left@ and no further action is taken.+Otherwise, if this parser fails __without__ consuming input, then @q@ is parsed instead and its result is+wrapped up using @Right@. If this parser fails having consumed input, this combinator fails.+This is functionally equivalent to @Left <$> p <|> Right <$> q@.++The reason for this behaviour is that it prevents space leaks and improves error messages. If this behaviour+is not desired, use @atomic p@ to rollback any input consumed on failure.++==== __Examples__+>>> p = string "abc" <+> char "xyz"+>>> parse p "abc"+Success (Left "abc")+>>> parse p "xyz"+Success (Right "xyz")+>>> parse p "ab"+Failure .. -- first parser consumed an 'a'!+-} (<+>) :: Parsec a -> Parsec b -> Parsec (Either a b) p <+> q = Left <$> p <|> Right <$> q -manyl :: (b -> a -> b) -> b -> Parsec a -> Parsec b+{-|+This combinator will parse this parser __zero__ or more times combining the results with the function @f@ and base value @k@ from the left.++This parser will continue to be parsed until it fails having __not consumed__ input.+All of the results generated by the successful parses are then combined in a left-to-right+fashion using the function @f@: the left-most value provided to @f@ is the value @k@.+If this parser does fail at any point having consumed input, this combinator will fail.+-}+manyl :: (b -> a -> b) -- ^ function to apply to each value produced by this parser, starting at the left.+ -> b -- ^ the initial value to feed into the reduction+ -> Parsec a+ -> Parsec b -- ^ a parser which parses this parser many times and folds the results together with @f@ and @k@ left-associatively. manyl f k = _repl f (pure k) -somel :: (b -> a -> b) -> b -> Parsec a -> Parsec b+{-|+This combinator will parse this parser __one__ or more times combining the results with the function @f@ and base value @k@ from the left.++This parser will continue to be parsed until it fails having __not consumed__ input.+All of the results generated by the successful parses are then combined in a left-to-right+fashion using the function @f@: the left-most value provided to @f@ is the value @k@.+If this parser does fail at any point having consumed input, this combinator will fail.++==== __Examples__+> natural = somel (\x d -> x * 10 + digitToInt d) 0 digit+-}+somel :: (b -> a -> b) -- ^ function to apply to each value produced by this parser, starting at the left.+ -> b -- ^ the initial value to feed into the reduction+ -> Parsec a+ -> Parsec b -- ^ a parser which parses this parser some times and folds the results together with @f@ and @k@ left-associatively. somel f k p = _repl f (f k <$> p) p {-|@@ -362,17 +443,48 @@ _repl f k p = k <**> manyr (\x next !acc -> next (f acc x)) id p -- should these be implemented with branch? probably not.-{-+{-|+This combinator filters the result of this parser using a given predicate, succeeding only if the predicate returns @True@. +First, parse this parser. If it succeeds then take its result @x@ and apply it to the predicate @pred@. If @pred x@ is+true, then return @x@. Otherwise, the combinator fails.++==== __Examples__+>>> keywords = Set.fromList ["if", "then", "else"]+>>> identifier = filterS (\v -> not (Set.member v keywords)) (some letter)+>>> parse identifier "hello"+Success "hello"+>>> parse identifier "if"+Failure ..+ @since 0.2.2.0 -}-filterS :: (a -> Bool) -> Parsec a -> Parsec a+filterS :: (a -> Bool) -- ^ the predicate that is tested against the parser result.+ -> Parsec a -- ^ the parser to filter, @p@.+ -> Parsec a -- ^ a parser that returns the result of @p@ if it passes the predicate. filterS = filterSWith vanillaGen -- this is called mapFilter in Scala... there is no collect counterpart-{-+{-|+This combinator applies a function @f@ to the result of this parser: if it returns a+@Just y@, @y@ is returned, otherwise the parser fails. +First, parse this parser. If it succeeds, apply the function @f@ to the result @x@. If+@f x@ returns @Just y@, return @y@. If @f x@ returns @Nothing@, or this parser failed+then this combinator fails. Is a more efficient way of performing a @filterS@ and @fmap@+at the same time.++==== __Examples__+>>> int = ...+>>> safeDiv = mapMaybeS (\(x, y) -> if y /= 0 then Just (div x y) else Nothing) (int <~> (char ' ' *> int))+>>> parse safeDiv "7 0"+Failure .. -- y cannot be 0!+>>> parse safeDiv "10 2"+Success 5+ @since 0.2.2.0 -}-mapMaybeS :: (a -> Maybe b) -> Parsec a -> Parsec b+mapMaybeS :: (a -> Maybe b) -- ^ the function used to both filter the result of this parser and transform it.+ -> Parsec a -- ^ the parser to filter, @p@.+ -> Parsec b -- ^ a parser that returns the result of @p@ applied to @f@, if it yields a value. mapMaybeS = mapMaybeSWith vanillaGen
src/Text/Gigaparsec/Combinator.hs view
@@ -48,7 +48,7 @@ -- * Selective Combinators -- | These combinators allow for the conditional extraction of a result, or the execution of a parser- -- based on another. They are derived from "branch".+ -- based on another. They are derived from 'Text.Gigaparsec.branch'. ifS, whenS, guardS, whileS, ) where
src/Text/Gigaparsec/Errors/Combinator.hs view
@@ -124,7 +124,10 @@ hide (Internal.Parsec p) = Internal.Parsec $ \st good bad -> let !origConsumed = Internal.consumed st- good' x st' = good x st' { Internal.hints = Internal.hints st } -- TODO: should this change valid offset?+ good' x st' = good x st' {+ Internal.hints = Internal.hints st,+ Internal.hintsValidOffset = Internal.hintsValidOffset st+ } bad' err st' | Internal.consumed st' /= origConsumed = bad err st' | otherwise = Internal.useHints bad (Internal.emptyErr st' 0) st'
src/Text/Gigaparsec/Internal.hs view
@@ -154,12 +154,40 @@ {-# INLINE many #-} {-# INLINE some #-} +{-|+This combinator will parse this parser __zero__ or more times combining the results with the function @f@ and base value @k@ from the right.++This parser will continue to be parsed until it fails having __not consumed__ input.+All of the results generated by the successful parses are then combined in a right-to-left+fashion using the function @f@: the right-most value provided to @f@ is the value @k@.+If this parser does fail at any point having consumed input, this combinator will fail.++==== __Examples__+> many = manyr (:) []+-} {-# INLINE manyr #-}-manyr :: (a -> b -> b) -> b -> Parsec a -> Parsec b+manyr :: (a -> b -> b) -- ^ function to apply to each value produced by this parser, starting at the right.+ -> b -- ^ value to use when this parser no longer succeeds.+ -> Parsec a+ -> Parsec b -- ^ a parser which parses this parser many times and folds the results together with @f@ and @k@ right-associatively. manyr f k p = let go = liftA2 f p go <|> pure k in go +{-|+This combinator will parse this parser __one__ or more times combining the results with the function @f@ and base value @k@ from the right.++This parser will continue to be parsed until it fails having __not consumed__ input.+All of the results generated by the successful parses are then combined in a right-to-left+fashion using the function @f@: the right-most value provided to @f@ is the value @k@.+If this parser does fail at any point having consumed input, this combinator will fail.++==== __Examples__+> some = somer (:) []+-} {-# INLINE somer #-}-somer :: (a -> b -> b) -> b -> Parsec a -> Parsec b+somer :: (a -> b -> b) -- ^ function to apply to each value produced by this parser, starting at the right.+ -> b -- ^ value to use when this parser no longer succeeds.+ -> Parsec a+ -> Parsec b -- ^ a parser which parses this parser some times and folds the results together with @f@ and @k@ right-associatively. somer f k p = liftA2 f p (manyr f k p) instance Semigroup m => Semigroup (Parsec m) where
src/Text/Gigaparsec/Token/Errors.hs view
@@ -2,33 +2,32 @@ {-# LANGUAGE NoMonomorphismRestriction, BlockArguments, OverloadedLists, OverloadedStrings #-} {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} module Text.Gigaparsec.Token.Errors (- ErrorConfig(- labelNumericBreakChar, labelIntegerUnsignedDecimal,- labelIntegerUnsignedHexadecimal, labelIntegerUnsignedOctal,- labelIntegerUnsignedBinary, labelIntegerUnsignedNumber,- labelIntegerSignedDecimal,- labelIntegerSignedHexadecimal, labelIntegerSignedOctal,- labelIntegerSignedBinary, labelIntegerSignedNumber,- labelIntegerDecimalEnd,- labelIntegerHexadecimalEnd, labelIntegerOctalEnd,- labelIntegerBinaryEnd, labelIntegerNumberEnd,- filterIntegerOutOfBounds,- labelNameIdentifier, labelNameOperator,- unexpectedNameIllegalIdentifier, unexpectedNameIllegalOperator,- filterNameIllFormedIdentifier, filterNameIllFormedOperator,- labelCharAscii, labelCharLatin1, labelCharUnicode,- labelCharAsciiEnd, labelCharLatin1End, labelCharUnicodeEnd,- labelStringAscii, labelStringLatin1, labelStringUnicode,- labelStringAsciiEnd, labelStringLatin1End, labelStringUnicodeEnd,- labelStringCharacter, labelGraphicCharacter, labelEscapeSequence,- labelEscapeNumeric, labelEscapeNumericEnd, labelEscapeEnd,- labelStringEscapeEmpty, labelStringEscapeGap, labelStringEscapeGapEnd,- filterCharNonAscii, filterCharNonLatin1, filterStringNonAscii, filterStringNonLatin1,- filterEscapeCharRequiresExactDigits, filterEscapeCharNumericSequenceIllegal,- verifiedCharBadCharsUsedInLiteral, verifiedStringBadCharsUsedInLiteral,- labelSymbol, labelSymbolEndOfKeyword, labelSymbolEndOfOperator,- labelSpaceEndOfLineComment, labelSpaceEndOfMultiComment- ),+ ErrorConfig,+ labelNumericBreakChar, labelIntegerUnsignedDecimal,+ labelIntegerUnsignedHexadecimal, labelIntegerUnsignedOctal,+ labelIntegerUnsignedBinary, labelIntegerUnsignedNumber,+ labelIntegerSignedDecimal,+ labelIntegerSignedHexadecimal, labelIntegerSignedOctal,+ labelIntegerSignedBinary, labelIntegerSignedNumber,+ labelIntegerDecimalEnd,+ labelIntegerHexadecimalEnd, labelIntegerOctalEnd,+ labelIntegerBinaryEnd, labelIntegerNumberEnd,+ filterIntegerOutOfBounds,+ labelNameIdentifier, labelNameOperator,+ unexpectedNameIllegalIdentifier, unexpectedNameIllegalOperator,+ filterNameIllFormedIdentifier, filterNameIllFormedOperator,+ labelCharAscii, labelCharLatin1, labelCharUnicode,+ labelCharAsciiEnd, labelCharLatin1End, labelCharUnicodeEnd,+ labelStringAscii, labelStringLatin1, labelStringUnicode,+ labelStringAsciiEnd, labelStringLatin1End, labelStringUnicodeEnd,+ labelStringCharacter, labelGraphicCharacter, labelEscapeSequence,+ labelEscapeNumeric, labelEscapeNumericEnd, labelEscapeEnd,+ labelStringEscapeEmpty, labelStringEscapeGap, labelStringEscapeGapEnd,+ filterCharNonAscii, filterCharNonLatin1, filterStringNonAscii, filterStringNonLatin1,+ filterEscapeCharRequiresExactDigits, filterEscapeCharNumericSequenceIllegal,+ verifiedCharBadCharsUsedInLiteral, verifiedStringBadCharsUsedInLiteral,+ labelSymbol, labelSymbolEndOfKeyword, labelSymbolEndOfOperator,+ labelSpaceEndOfLineComment, labelSpaceEndOfMultiComment, defaultErrorConfig, LabelWithExplainConfig, LabelWithExplainConfigurable(..), LabelConfig, LabelConfigurable(..),
test/Text/Gigaparsec/ErrorsTests.hs view
@@ -394,4 +394,10 @@ testParse (amend greeting <?> ["greeting"]) "hello world." @?= Failure (TestError (1, 1) (VanillaError (Just (Raw "h")) [Named "greeting"] [] 1)) ]+ , testGroup "hide should"+ [ testCase "not revive dead hints" do+ let p = optional digit <* char ']' <* hide (optional letter) <* eof+ testParse p "]1" @?=+ Failure (TestError (1, 2) (VanillaError (Just (Raw "1")) [EndOfInput] [] 1))+ ] ]