[
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## Build generated\nbuild/\nDerivedData\n.build/\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata\n\n## Other\n*.xccheckout\n*.moved-aside\n*.xcuserstate\n*.xcscmblueprint\n.DS_Store\n.swift-version\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control\n#\n# Pods/\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\n# Carthage/Checkouts\n\nCarthage/Build\n\n# fastlane\n#\n# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the \n# screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md\n\nfastlane/report.xml\nfastlane/screenshots\n"
  },
  {
    "path": ".travis.yml",
    "content": "os: osx\nosx_image: xcode8\nlanguage: objective-c\n\n\nmatrix:\n  include:\n    - env: XCODE_DESTINATION=\"platform=iOS Simulator,OS=10.0,name=iPhone 5s\"\n    - env: XCODE_DESTINATION=\"platform=iOS Simulator,OS=10.0,name=iPhone 6\"\n    - env: XCODE_DESTINATION=\"platform=iOS Simulator,OS=10.0,name=iPhone 6s Plus\"\n    - env: XCODE_DESTINATION=\"platform=iOS Simulator,OS=10.0,name=iPad Air\"\n    - env: XCODE_DESTINATION=\"platform=iOS Simulator,OS=10.0,name=iPad Air 2\"\n    - env: XCODE_DESTINATION=\"platform=iOS Simulator,OS=10.0,name=iPad Pro (12.9 inch)\"\n    - env: XCODE_DESTINATION=\"platform=iOS Simulator,OS=10.0,name=iPad Retina\"\n    - os: linux\n      dist: trusty\n      language: generic\n\n\n# BUG FIX: https://github.com/travis-ci/travis-ci/issues/6307\nbefore_install: rvm get head\n\n\ninstall: . ./scripts/install-swift.sh\n\n\nscript: ./scripts/run-tests.sh\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Release 4.0.1\n\nFix compilation error in Xcode 12.5\n\n# Release 4.0.0\n\nMigrated source code to Swift 5.0\n\n# Release 3.0.3\n\nAdd missing 'products' entry in package description\n\n# Release 3.0.2\n\nUpdate package description\n\n# Release 3.0.1\n\nFix compilation error for Swift 4.2\n\n# Release 3.0.0\n\nMigrated source code to Swift 4.0\n\n# Release 2.1\n\nAdded support for linux.\n\n# Release 2.0.1\n\nMoved operators implementation in `Parsec` extension\n\n# Release 2.0\n\n## General\n\n- Migrated source code to Swift 3.0\n- Now Support Swift Package Manager\n- Improved files and source code layout\n- More documentation\n\n## Performance\n\nA benchmark was added to test the performance of the library.\n\nAn internal design modification greatly improved the parsing speed and memory\nusage. Before the modification the benchmark measured 648.32s (≈10.8m) to\nexecute the parsing of a huge JSON file. Now it only takes 6.7s, a bit more than\n96 times faster!\n\n## API\n\n- Added the `userState: GenericParser<StreamType, UserState, UserState>`\nparser.\n- Now the `run(userState: UserState, sourceName: String, input: StreamType)\nthrows -> Result` only returns the result of the parsing. As an example, if one\nwants to get the user state and the result at the same time:\n```\nlet countLine = GenericParser<String, Int, Character>.endOfLine >>- { newLine in\n\n    GenericParser<String, Int, Int>.userState >>- { userState in\n\n        GenericParser(result: (newLine, userState + 1))\n\n    }\n\n}\n\n```\n- Added the `Parsec.runSafe(userState: UserState, sourceName: String,\ninput: StreamType) -> Either<ParseError, Result>` method. This new method does\nnot throw exceptions but returns the result wrap in an `Either` type.\n- Added a parser returning the current source position:\n`GenericParser.sourcePosition: GenericParser<StreamType, UserState, SourcePosition>`\n- Various minor changes to conform to the Swift API design guide lines\n\n# Release 1.1\n\n- Fixed wrong parse error type returned by `GenericParser.unexpected()`\n- Added missing guard statement to prevent crash in `UnicodeScalar.fromUInt32()`\n- Added `ClosedInterval` variant of `ParsecType.oneOf()`\n- Migration to Swift 2.2\n- Internal code improvement\n- Increased tests coverage\n- Documentation improvement\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2015, David Dufresne\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\nthis list of conditions and the following disclaimer in the documentation\nand/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:4.2\n// The swift-tools-version declares the minimum version of Swift required to build this package.\n//\n//  Package.swift\n//  SwiftParsec\n//\n//  Created by David Dufresne on 2016-05-10.\n//  Copyright © 2016 David Dufresne. All rights reserved.\n//\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"SwiftParsec\",\n    products: [\n        // Products define the executables and libraries produced by a package, and\n        // make them visible to other packages.\n        .library(\n            name: \"SwiftParsec\",\n            targets: [\"SwiftParsec\"]\n        ),\n    ],\n    targets: [\n        .target(name: \"SwiftParsec\"),\n    ]\n)\n"
  },
  {
    "path": "README.md",
    "content": "# SwiftParsec\nSwiftParsec is a Swift port of the [Parsec](https://github.com/aslatter/parsec) parser combinator library. It allows the creation of sophisticated parsers from a set of simple parsers. It is also easy to extend the available parsers. The parsers are fully integrated into the language, they can be put into arrays, passed as parameters, returned as values, etc. SwiftParsec provides expressiveness, is well documented and simple.\n\n# Key Features\n- Reusable combinators\n- Lexical analysis\n- Expression parser\n- Permutation phrases parser\n- Extensive error messages\n- Unicode support\n\n# Documentation\nSee the [wiki](https://github.com/davedufresne/SwiftParsec/wiki)\n\n# License\nSwiftParsec is released under the “Simplified BSD License”. See the LICENSE file in the repository.\n"
  },
  {
    "path": "Sources/SwiftParsec/CharacterConversion.swift",
    "content": "//==============================================================================\n// CharacterConversion.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2016-09-24.\n// Copyright © 2016 David Dufresne. All rights reserved.\n//\n// Character extension\n//==============================================================================\n\n//==============================================================================\n// Extension containing methods related to the conversion of a character.\nextension Character {\n    \n    /// The first `UnicodeScalar` of `self`.\n    var unicodeScalar: UnicodeScalar {\n        \n        let unicodes = String(self).unicodeScalars\n        return unicodes[unicodes.startIndex]\n        \n    }\n    \n    /// Lowercase `self`.\n    var lowercase: Character {\n        \n        let str = String(self).lowercased()\n        return str[str.startIndex]\n        \n    }\n    \n    /// Uppercase `self`.\n    var uppercase: Character {\n        \n        let str = String(self).uppercased()\n        return str[str.startIndex]\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/CharacterMembership.swift",
    "content": "//==============================================================================\n// CharacterMembership.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-19.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// Character extension\n//==============================================================================\n\nprivate let uppercaseSet = CharacterSet.uppercaseLetters\nprivate let lowercaseSet = CharacterSet.lowercaseLetters\nprivate let alphaSet = CharacterSet.letters\nprivate let alphaNumericSet = CharacterSet.alphanumerics\nprivate let symbolSet = CharacterSet.symbols\nprivate let digitSet = CharacterSet.decimalDigits\n\n//==============================================================================\n// Extension containing methods to test if a character is a member of a\n// character set.\nextension Character {\n    \n    /// True for any space character, and the control characters \\t, \\n, \\r, \\f,\n    /// \\v.\n    var isSpace: Bool {\n        \n        switch self {\n            \n        case \" \", \"\\t\", \"\\n\", \"\\r\", \"\\r\\n\": return true\n            \n        case \"\\u{000B}\", \"\\u{000C}\": return true // Form Feed, vertical tab\n           \n        default: return false\n            \n        }\n        \n    }\n    \n    /// True for any Unicode space character, and the control characters \\t, \\n,\n    /// \\r, \\f, \\v.\n    var isUnicodeSpace: Bool {\n        \n        switch self {\n            \n        case \" \", \"\\t\", \"\\n\", \"\\r\", \"\\r\\n\": return true\n            \n        // Form Feed, vertical tab, next line (nel)\n        case \"\\u{000C}\", \"\\u{000B}\", \"\\u{0085}\": return true\n            \n        // No-break space, ogham space mark, mongolian vowel\n        case \"\\u{00A0}\", \"\\u{1680}\", \"\\u{180E}\": return true\n            \n        // En quad, em quad, en space, em space, three-per-em space, four-per-em\n        // space, six-per-em space, figure space, ponctuation space, thin space,\n        // hair space, zero width space, zero width non-joiner, zero width\n        // joiner.\n        case \"\\u{2000}\", \"\\u{2001}\", \"\\u{2002}\", \"\\u{2003}\", \"\\u{2004}\",\n             \"\\u{2005}\", \"\\u{2006}\", \"\\u{2007}\", \"\\u{2008}\", \"\\u{2009}\",\n             \"\\u{200A}\", \"\\u{200B}\", \"\\u{200C}\", \"\\u{200D}\":\n            \n            return true\n            \n        // Line separator, paragraph separator.\n        case \"\\u{2028}\", \"\\u{2029}\": return true\n            \n        // Narrow no-break space, medium mathematical space, word joiner,\n        // ideographic space, zero width no-break space.\n        case \"\\u{202F}\", \"\\u{205F}\", \"\\u{2060}\", \"\\u{3000}\", \"\\u{FEFF}\":\n            \n            return true\n            \n        default: return false\n            \n        }\n        \n    }\n    \n    /// `true` if `self` normalized contains a single code unit that is in the\n    /// categories of Uppercase and Titlecase Letters.\n    var isUppercase: Bool {\n        \n        return isMember(of: uppercaseSet)\n        \n    }\n    \n    /// `true` if `self` normalized contains a single code unit that is in the\n    /// category of Lowercase Letters.\n    var isLowercase: Bool {\n        \n        return isMember(of: lowercaseSet)\n        \n    }\n    \n    /// `true` if `self` normalized contains a single code unit that is in the\n    /// categories of Letters and Marks.\n    var isAlpha: Bool {\n        \n        return isMember(of: alphaSet)\n        \n    }\n    \n    /// `true` if `self` normalized contains a single code unit that is in th\n    /// categories of Letters, Marks, and Numbers.\n    var isAlphaNumeric: Bool {\n        \n        return isMember(of: alphaNumericSet)\n        \n    }\n    \n    /// `true` if `self` normalized contains a single code unit that is in the\n    /// category of Symbols. These characters include, for example, the dollar\n    /// sign ($) and the plus (+) sign.\n    var isSymbol: Bool {\n        \n        return isMember(of: symbolSet)\n        \n    }\n    \n    /// `true` if `self` normalized contains a single code unit that is in the\n    /// category of Decimal Numbers.\n    var isDigit: Bool {\n        \n        return isMember(of: digitSet)\n        \n    }\n    \n    /// `true` if `self` is an ASCII decimal digit, i.e. between \"0\" and \"9\".\n    var isDecimalDigit: Bool {\n        \n        return \"0123456789\".contains(self)\n        \n    }\n    \n    /// `true` if `self` is an ASCII hexadecimal digit, i.e. \"0\"...\"9\",\n    /// \"a\"...\"f\", \"A\"...\"F\".\n    var isHexadecimalDigit: Bool {\n        \n        return \"01234567890abcdefABCDEF\".contains(self)\n        \n    }\n    \n    /// `true` if `self` is an ASCII octal digit, i.e. between '0' and '7'.\n    var isOctalDigit: Bool {\n        \n        return \"01234567\".contains(self)\n        \n    }\n    \n    /// Return `true` if `self` normalized contains a single code unit that is a\n    /// member of the supplied character set.\n    ///\n    /// - parameter set: The `NSCharacterSet` used to test for membership.\n    /// - returns: `true` if `self` normalized contains a single code unit that\n    ///   is a member of the supplied character set.\n    func isMember(of set: CharacterSet) -> Bool {\n        \n        let normalized = String(self).precomposedStringWithCanonicalMapping\n        let unicodes = normalized.unicodeScalars\n        \n        guard unicodes.count == 1 else { return false }\n        \n        return set.contains(unicodes.first!)\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/CharacterParsers.swift",
    "content": "//==============================================================================\n// CharacterParsers.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-16.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// Commonly used character parsers.\n//==============================================================================\n\n/// String parser with an empty `UserState`.\npublic typealias StringParser = GenericParser<String, (), Character>\n\n//==============================================================================\n// Extension containing methods related to character parsing.\npublic extension Parsec\nwhere StreamType.Iterator.Element == Character, Result == Character {\n    \n    /// Return a parser that succeeds for any character for which the supplied\n    /// function `predicate` returns `true`. The parser returns the character\n    /// that is actually parsed.\n    ///\n    /// - parameter predicate: The predicate to apply on the `Character`.\n    /// - returns: A parser that succeeds for any character for which the\n    ///   supplied function `predicate` returns `true`.\n    static func satisfy(\n        _ predicate: @escaping (Character) -> Bool\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        return tokenPrimitive(\n            tokenDescription: { String(reflecting: $0) },\n            nextPosition: { position, elem in\n                \n                var pos = position\n                pos.updatePosition(elem)\n                \n                return pos\n                \n            },\n            match: { elem in\n                \n                predicate(elem) ? elem : nil\n                \n            })\n        \n    }\n    \n    /// Return a parser that succeeds if the current character is in the\n    /// supplied list of characters. It returns the parsed character.\n    ///\n    ///     let vowel = StringParser.oneOf(\"aeiou\")\n    ///\n    /// - parameter list: A `String` of possible characters to match.\n    /// - returns: A parser that succeeds if the current character is in the\n    ///   supplied list of characters.\n    /// - SeeAlso:\n    ///   `GenericParser.satisfy(\n    ///       predicate: Character -> Bool\n    ///   ) -> GenericParser`\n    static func oneOf(\n        _ list: String\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy(list.contains)\n        \n    }\n    \n    /// Return a parser that succeeds if the current character is in the\n    /// supplied interval of characters. It returns the parsed character.\n    ///\n    ///     let digit = StringParser.oneOf(\"0\"...\"9\")\n    ///\n    /// - parameter interval: A `ClosedInterval` of possible characters to\n    ///   match.\n    /// - returns: A parser that succeeds if the current character is in the\n    ///   supplied interval of characters.\n    /// - SeeAlso:\n    ///   `GenericParser.satisfy(\n    ///       predicate: Character -> Bool\n    ///   ) -> GenericParser`\n    static func oneOf(\n        _ interval: ClosedRange<Character>\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy(interval.contains)\n        \n    }\n    \n    /// Return a parser that succeeds if the current character is _not_ in the\n    /// supplied list of characters. It returns the parsed character.\n    ///\n    ///     let consonant = StringParser.noneOf(\"aeiou\")\n    ///\n    /// - parameter list: A `String` of possible _not_ to match.\n    /// - returns: A parser that succeeds if the current character is _not_ in\n    ///   the supplied list of characters.\n    static func noneOf(\n        _ list: String\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { !list.contains($0) }\n        \n    }\n    \n    /// A Parser that skips _zero_ or more unicode white space characters.\n    ///\n    /// - SeeAlso: `GenericParser.skipMany`.\n    static var spaces: GenericParser<StreamType, UserState, ()> {\n        \n        return space.skipMany <?> LocalizedString(\"white space\")\n        \n    }\n    \n    /// A Parser that parses a white space character (any Unicode space\n    /// character, and the control characters \\t, \\n, \\r, \\f, \\v). It returns\n    /// the parsed character.\n    static var unicodeSpace:\n        GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isUnicodeSpace } <?> LocalizedString(\"unicode space\")\n        \n    }\n    \n    /// A Parser that parses any space character, and the control characters \\t,\n    /// \\n, \\r, \\f, \\v. It returns the parsed character.\n    static var space: GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isSpace } <?> LocalizedString(\"space\")\n        \n    }\n    \n    /// A Parser that parses a newline character (\"\\n\"). It returns a newline\n    /// character.\n    static var newLine: GenericParser<StreamType, UserState, Result> {\n        \n        return character(\"\\n\") <?> LocalizedString(\"lf new-line\")\n        \n    }\n    \n    /// A Parser that parses a carriage return character (\"\\r\") followed by a\n    /// newline character (\"\\n\"). It returns a newline character.\n    static var crlf: GenericParser<StreamType, UserState, Result> {\n        \n        // \"\\r\\n\" is combined in one Unicode Scalar.\n        return character(\"\\r\\n\") *> GenericParser(result: \"\\n\") <|>\n            character(\"\\r\") *> character(\"\\n\") <?>\n            LocalizedString(\"crlf new-line\")\n        \n    }\n    \n    /// A Parser that parses a CRLF (see `crlf`) or LF (see `newLine`)\n    /// end-of-line. It returns a newline character (\"\\n\").\n    ///\n    ///     let endOfLine = StringParser.newline <|> StringParser.crlf\n    static var endOfLine: GenericParser<StreamType, UserState, Result> {\n        \n        return newLine <|> crlf <?> LocalizedString(\"new-line\")\n        \n    }\n    \n    /// A Parser that parses a tab character (\"\\t\"). It returns a tab character.\n    static var tab: GenericParser<StreamType, UserState, Result> {\n        \n        return character(\"\\t\") <?> LocalizedString(\"tab\")\n        \n    }\n    \n    /// A Parser that parses a character in the category of Uppercase and\n    /// Titlecase Letters. It returns the parsed character.\n    static var uppercase: GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isUppercase } <?> LocalizedString(\"uppercase letter\")\n        \n    }\n    \n    /// A Parser that parses a character in the category of Lowercase Letters.\n    /// It returns the parsed character.\n    static var lowercase: GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isLowercase } <?> LocalizedString(\"lowercase letter\")\n        \n    }\n    \n    /// A Parser that parses a character in the categories of Letters, Marks,\n    /// and Numbers. It returns the parsed character.\n    static var alphaNumeric:\n        GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isAlphaNumeric } <?>\n            LocalizedString(\"letter or digit\")\n        \n    }\n    \n    /// A Parser that parses a character in the categories of Letters and Marks.\n    /// It returns the parsed character.\n    static var letter: GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isAlpha } <?> LocalizedString(\"letter\")\n        \n    }\n    \n    /// A Parser that parses a character in the categories of Symbols. It\n    /// returns the parsed character.\n    static var symbol: GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isSymbol } <?> LocalizedString(\"symbol\")\n        \n    }\n    \n    /// A Parser that parses a character in the category of Numbers. It returns\n    /// the parsed character.\n    static var digit: GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isDigit } <?> LocalizedString(\"digit\")\n        \n    }\n    \n    /// A Parser that parses an ASCII decimal digit, i.e. between \"0\" and \"9\".\n    /// It returns the parsed character.\n    static var decimalDigit:\n        GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isDecimalDigit } <?> LocalizedString(\"digit\")\n        \n    }\n    \n    /// A Parser that parses an ASCII hexadecimal digit, i.e. \"0\"...\"9\",\n    /// \"a\"...\"f\", \"A\"...\"F\". It returns the parsed character.\n    static var hexadecimalDigit:\n        GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isHexadecimalDigit } <?>\n            LocalizedString(\"hexadecimal digit\")\n        \n    }\n    \n    /// A Parser that parses an octal digit (a character between \"0\" and \"7\").\n    /// It returns the parsed character.\n    static var octalDigit: GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isOctalDigit } <?>  LocalizedString(\"octal digit\")\n        \n    }\n    \n    /// Return a parser that parses a single character `Character`. It returns\n    /// the parsed character (i.e. `char`).\n    ///\n    ///     let semicolon  = StringParser.character(\";\")\n    ///\n    /// - parameter char: The character to parse.\n    /// - returns: A parser that parses a single character `Character`.\n    static func character(\n        _ char: Character\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0 == char } <?> String(reflecting: char)\n        \n    }\n    \n    /// A Parser that succeeds for any character. It returns the parsed\n    /// character.\n    static var anyCharacter:\n        GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { _ in true }\n        \n    }\n    \n    /// A Parser that maps a `Character` to a `String`.\n    var stringValue: GenericParser<StreamType, UserState, String> {\n        \n        return map { String($0) }\n        \n    }\n    \n    /// Return a parser that succeeds for any character that are member of the\n    /// supplied `CharacterSet`. It returns the parsed character.\n    ///\n    /// - parameter set: The `CharacterSet` used to test for membership.\n    /// - returns: The parsed character.\n    static func memberOf(\n        _ set: CharacterSet\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        return satisfy { $0.isMember(of: set) }\n        \n    }\n    \n}\n\n//==============================================================================\n// Extension containing methods related to result conversion.\npublic extension Parsec\nwhere Result: Sequence, Result.Iterator.Element == Character {\n    \n    /// A Parser that maps an array of `Character` to a `String`.\n    var stringValue: GenericParser<StreamType, UserState, String> {\n        \n        return map { String($0) }\n        \n    }\n    \n}\n\n//==============================================================================\n// Extension containing methods related to string parsing.\npublic extension Parsec\nwhere StreamType.Iterator.Element == Character {\n    \n    /// Return a parser that parses a `String`. It returns the parsed string\n    /// (i.e. `str`).\n    ///\n    ///     let divOrMod = StringParser.string(\"div\") <|>\n    ///         StringParser.string(\"mod\")\n    ///\n    /// - parameter str: The string to parse.\n    /// - returns: A parser that parses a `String`.\n    static func string(\n        _ str: StreamType\n    ) -> GenericParser<StreamType, UserState, StreamType> {\n        \n        return tokens(\n            tokensDescription: { String(reflecting: $0) },\n            nextPosition: { position, charStreamType in\n                \n                var pos = position\n                for char in charStreamType {\n                    \n                    pos.updatePosition(char)\n                    \n                }\n                \n                return pos\n                \n            },\n            tokens: str)\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/CharacterSet.swift",
    "content": "//==============================================================================\n// CharacterSet.swift\n// SwiftParsec\n//\n// CharacterSet compatibility wrapper\n//==============================================================================\n\nimport struct Foundation.CharacterSet\n\n#if _runtime(_ObjC)\n\n/// Ideally, we could use this for all platforms, but open-source\n/// `Foundation.CharacterSet` will fail at large sizes\npublic typealias CharacterSet = Foundation.CharacterSet\n\n#else\n\n//==============================================================================\n/// The `CharacterSet` is a thin wrapper around `Foundation.CharacterSet`. It\n/// helps us avoid bugs in open-source version.\npublic struct CharacterSet {\n    \n    /// Indicates whether the set contains the given unicode character.\n    public let contains: (UnicodeScalar) -> Bool\n    \n    /// Convenience factory for `Foundation.CharacterSet#uppercaseLetters`\n    public static var uppercaseLetters: CharacterSet {\n        \n        return CharacterSet(Foundation.CharacterSet.uppercaseLetters)\n        \n    }\n    \n    /// Convenience factory for `Foundation.CharacterSet#lowercaseLetters`\n    public static var lowercaseLetters: CharacterSet {\n        \n        return CharacterSet(Foundation.CharacterSet.lowercaseLetters)\n        \n    }\n    \n    /// Convenience factory for `Foundation.CharacterSet#decimalDigits`\n    public static var decimalDigits: CharacterSet {\n        \n        return CharacterSet(Foundation.CharacterSet.decimalDigits)\n        \n    }\n    \n    /// Convenience factory for `Foundation.CharacterSet#symbols`\n    public static var symbols: CharacterSet {\n        \n        return CharacterSet(Foundation.CharacterSet.symbols)\n        \n    }\n    \n    /// Convenience factory for `Foundation.CharacterSet#letters`\n    public static var letters: CharacterSet {\n        \n        return CharacterSet(Foundation.CharacterSet.letters)\n        \n    }\n    \n    /// Convenience factory for `Foundation.CharacterSet#alphanumerics`\n    public static var alphanumerics: CharacterSet {\n        \n        return CharacterSet(Foundation.CharacterSet.alphanumerics)\n        \n    }\n    \n    /// Alternative to `Foundation.CharacterSet#init` that does not fail for\n    /// large inputs. It is likely less performant.\n    public init(charactersIn: String) {\n        \n        self.contains = Set(charactersIn.unicodeScalars).contains\n        \n    }\n    \n    /// Convert a `Foundation.CharacterSet` to a `SwiftParsec.CharacterSet`\n    public init(_ foundationSet: Foundation.CharacterSet) {\n        \n        self.contains = foundationSet.contains\n        \n    }\n    \n}\n\n#endif\n"
  },
  {
    "path": "Sources/SwiftParsec/CollectionAggregation.swift",
    "content": "//==============================================================================\n// CollectionAggregation.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-09.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// Collection extension\n//==============================================================================\n\n//==============================================================================\n// Extension containing aggregation methods.\nextension Collection {\n    \n    /// Return the result of repeatedly calling `combine` with an accumulated\n    /// value initialized to `initial` and each element of `self`, in turn from\n    /// the right, i.e. return combine(combine(...combine(combine(initial,\n    /// self[count-1]), self[count-2]), self[count-3]), ... self[0]).\n    ///\n    /// - parameters:\n    ///   - initial: The initial value.\n    ///   - combine: The combining function.\n    /// - returns: The combined result of each element of `self`.\n    func reduceRight<T>(\n        _ initial: T,\n        combine: (T, Self.Iterator.Element) throws -> T\n    ) rethrows -> T {\n        \n        var acc = initial\n        for elem in reversed() {\n            \n            acc = try combine(acc, elem)\n            \n        }\n        \n        return acc\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/CombinatorParsers.swift",
    "content": "//==============================================================================\n// CombinatorParsers.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-26.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// Commonly used generic combinators\n//==============================================================================\n\n//==============================================================================\n// Extension containing methods related to parser combinators.\npublic extension GenericParser {\n    \n    /// Return a parser that tries to apply the parsers in the array `parsers`\n    /// in order, until one of them succeeds. It returns the value of the\n    /// succeeding parser.\n    ///\n    /// - parameter parsers: An array of parsers to try.\n    /// - returns: A parser that tries to apply the parsers in the array\n    ///   `parsers` in order, until one of them succeeds.\n    static func choice<S: Sequence>(_ parsers: S) -> GenericParser\n    where S.Iterator.Element == GenericParser {\n        \n        return parsers.reduce(GenericParser.empty, <|>)\n        \n    }\n    \n    /// A parser that tries to apply `self`. If `self` fails without consuming\n    /// input, it returns `nil`, otherwise it returns the value returned by\n    /// `self`.\n    var optional: GenericParser<StreamType, UserState, Result?> {\n        \n        return map({ $0 }).otherwise(nil)\n        \n    }\n    \n    /// Return a parser that tries to apply `self`. If `self` fails without\n    /// consuming input, it returns `result`, or else the value returned by\n    /// `self`.\n    ///\n    /// - parameter result: The result to return if `self` fails without\n    ///   consuming input.\n    /// - returns: A parser that tries to apply `self`. If `self` fails without\n    ///   consuming input, it returns `result`.\n    func otherwise(_ result: Result) -> GenericParser {\n        \n        return self <|> GenericParser(result: result)\n        \n    }\n    \n    /// A parser that tries to apply `self`. It will parse `self` or nothing.\n    /// It only fails if `self` fails after consuming input. It discards the\n    /// result of `self`.\n    var discard: GenericParser<StreamType, UserState, ()> {\n        \n        return map { _ in () } <|> GenericParser<StreamType, UserState, ()>(\n            result: ()\n        )\n        \n    }\n    \n    /// Return a parser that parses `opening`, followed by `self` and `closing`.\n    /// It returns the value returned by `self`.\n    ///\n    /// - parameters:\n    ///   - opening: The first parser to apply.\n    ///   - closing: The last parser to apply.\n    /// - returns: A parser that parses `opening`, followed by `self` and\n    ///   `closing`.\n    func between<U, V>(\n        _ opening: GenericParser<StreamType, UserState, U>,\n        _ closing: GenericParser<StreamType, UserState, V>\n    ) -> GenericParser {\n        \n        return opening *> self <* closing\n        \n    }\n    \n    /// A parser that applies `self` _one_ or more times, skipping its result.\n    var skipMany1: GenericParser<StreamType, UserState, ()> {\n        \n        return self >>- { _ in self.skipMany }\n        \n    }\n    \n    /// A parser that applies `self` _one_ or more times. It returns an array of\n    /// the returned values of `self`.\n    ///\n    ///     let word = StringParser.letter.many1\n    var many1: GenericParser<StreamType, UserState, [Result]> {\n        \n        return self >>- { result in\n            \n            self.many >>- { results in\n                \n                let rs = results.prepending(result)\n                return GenericParser<StreamType, UserState, [Result]>(\n                    result: rs\n                )\n                \n            }\n            \n        }\n        \n    }\n    \n    /// Return a parser that parses _zero_ or more occurrences of `self`,\n    /// separated by `separator`. It returns an array of values returned by\n    /// `self`.\n    ///\n    ///     let comma = StringParser.character(\",\")\n    ///     let letter = StringParser.letter\n    ///     let commaSeparated = letter.separatedBy(comma)\n    ///\n    /// - parameter separator: The separator parser.\n    /// - returns: A parser that parses _zero_ or more occurrences of `self`,\n    ///   separated by `separator`.\n    func separatedBy<Separator>(\n        _ separator: GenericParser<StreamType, UserState, Separator>\n    ) -> GenericParser<StreamType, UserState, [Result]> {\n        \n        return separatedBy1(separator) <|>\n            GenericParser<StreamType, UserState, [Result]>(result: [])\n        \n    }\n    \n    /// Return a parser that parses _one_ or more occurrences of `self`,\n    /// separated by `separator`. It returns an array of values returned by\n    /// `self`.\n    ///\n    /// - parameter separator: The separator parser.\n    /// - returns: A parser that parses _one_ or more occurrences of `self`,\n    ///   separated by `separator`.\n    func separatedBy1<Separator>(\n        _ separator: GenericParser<StreamType, UserState, Separator>\n    ) -> GenericParser<StreamType, UserState, [Result]> {\n        \n        return self >>- { result in\n            \n            (separator *> self).many >>- { results in\n                \n                let rs = results.prepending(result)\n                return GenericParser<StreamType, UserState, [Result]>(\n                    result: rs\n                )\n                \n            }\n            \n        }\n        \n    }\n    \n    /// Return a parser that parses _zero_ or more occurrences of `self`,\n    /// separated and optionally ended by `separator`. It returns an array of\n    /// values returned by `self`.\n    ///\n    ///     let cStatements = cStatement.dividedBy(semicolon)\n    ///\n    ///     let swiftStatements = swiftStatement.dividedBy(semicolon,\n    ///         endSeparatorRequired: false)\n    ///\n    /// - parameters:\n    ///   - separator: The separator parser.\n    ///   - endSeparatorRequired: Indicates if the separator is required at the\n    ///     end. The default value is true.\n    /// - returns: A parser that parses _zero_ or more occurrences of `self`,\n    ///   separated and optionally ended by `separator`.\n    func dividedBy<Separator>(\n        _ separator: GenericParser<StreamType, UserState, Separator>,\n        endSeparatorRequired: Bool = true\n    ) -> GenericParser<StreamType, UserState, [Result]> {\n        \n        if endSeparatorRequired {\n            \n            return (self <* separator).many\n            \n        }\n        \n        return dividedBy1(separator, endSeparatorRequired: false) <|>\n            GenericParser<StreamType, UserState, [Result]>(result: [])\n        \n    }\n    \n    /// Return a parser that parses _one_ or more occurrences of `self`,\n    /// separated and optionally ended by `separator`. It returns an array of\n    /// values returned by `self`.\n    ///\n    /// - parameters:\n    ///   - separator: The separator parser.\n    ///   - endSeparatorRequired: Indicates if the separator is required at the\n    ///     end. The default value is true.\n    /// - returns: A parser that parses _one_ or more occurrences of `self`,\n    ///   separated and optionally ended by `separator`.\n    func dividedBy1<Separator>(\n        _ separator: GenericParser<StreamType, UserState, Separator>,\n        endSeparatorRequired: Bool = true\n    ) -> GenericParser<StreamType, UserState, [Result]> {\n        \n        if endSeparatorRequired {\n            \n            return (self <* separator).many1\n            \n        }\n        \n        return self >>- { result in\n            \n            // Type inference bug.\n            let optionalSeparator:\n                GenericParser<StreamType, UserState, [Result]> =\n            separator >>- { _ in\n                \n                self.dividedBy(separator, endSeparatorRequired: false) >>-\n                { results in\n                    \n                    let rs = results.prepending(result)\n                    return GenericParser<StreamType, UserState, [Result]>(\n                        result: rs\n                    )\n                    \n                }\n                \n            }\n            \n            return optionalSeparator <|>\n                GenericParser<StreamType, UserState, [Result]>(result: [result])\n            \n        }\n        \n    }\n    \n    /// Return a parser that parses `n` occurrences of `self`. If `n` is\n    /// smaller or equal to zero, the parser returns `[]`. It returns an array\n    /// of `n` values returned by `self`.\n    ///\n    /// - parameter n: The number of occurences of `self` to parse.\n    /// - returns: A parser that parses `n` occurrences of `self`.\n    func count(\n        _ n: Int\n    ) -> GenericParser<StreamType, UserState, [Result]> {\n        \n        func count(\n            _ n: Int,\n            results: [Result]\n        ) -> GenericParser<StreamType, UserState, [Result]> {\n            \n            guard n > 0 else {\n                \n                return GenericParser<StreamType, UserState, [Result]>(\n                    result: results\n                )\n                \n            }\n            \n            return self >>- { result in\n                \n                let rs = results.appending(result)\n                return count(n - 1, results: rs)\n                \n            }\n            \n        }\n        \n        return GenericParser<StreamType, UserState, [Result]> { state in\n            \n            return count(n, results: []).parse(state)\n            \n        }\n        \n    }\n    \n    /// Return a parser that parses _zero_ or more occurrences of `self`,\n    /// separated by `oper`. Returns a value obtained by a _right_ associative\n    /// application of all functions returned by `oper` to the values returned\n    /// by `self`. If there are no occurrences of `self`, the value `otherwise`\n    /// is returned.\n    ///\n    /// - parameters:\n    ///   - oper: The operator parser.\n    ///   - otherwise: Default value returned when there are no occurences of\n    ///     `self`.\n    /// - returns: A parser that parses _zero_ or more occurrences of `self`,\n    ///   separated by `oper`.\n    func chainRight(\n        _ oper: GenericParser<StreamType, UserState, (Result, Result) -> Result>,\n        otherwise: Result\n    ) -> GenericParser {\n    \n        return chainRight1(oper) <|> GenericParser(result: otherwise)\n        \n    }\n    \n    /// Return a parser that parses _one_ or more occurrences of `self`,\n    /// separated by `oper`. Returns a value obtained by a _right_ associative\n    /// application of all functions returned by `op` to the values returned by\n    /// `self`.\n    ///\n    /// - parameter oper: The operator parser.\n    /// - returns: A parser that parses _one_ or more occurrences of `self`,\n    ///   separated by `oper`.\n    func chainRight1(\n        _ oper: GenericParser<StreamType, UserState, (Result, Result) -> Result>\n    ) -> GenericParser {\n        \n        func scan() -> GenericParser {\n            \n            return self >>- { result in rest(result) }\n            \n        }\n        \n        func rest(_ left: Result) -> GenericParser {\n            \n            // Type inference bug.\n            let operParser: GenericParser = oper >>- { op in\n                \n                scan() >>- { right in\n                    \n                    let result = op(left, right)\n                    return GenericParser(result: result)\n                    \n                }\n                \n            }\n            \n            return operParser <|> GenericParser(result: left)\n            \n        }\n        \n        return scan()\n        \n    }\n    \n    /// Return a parser that parses _zero_ or more occurrences of `self`,\n    /// separated by `oper`. Returns a value obtained by a _left_ associative\n    /// application of all functions returned by `oper` to the values returned\n    /// by `self`. If there are zero occurrences of `self`, the value\n    /// `otherwise` is returned.\n    ///\n    /// - parameters:\n    ///   - oper: The operator parser.\n    ///   - otherwise: Default value returned when there are no occurences of\n    ///     `self`.\n    /// - returns: A parser that parses _zero_ or more occurrences of `self`,\n    ///   separated by `oper`.\n    func chainLeft(\n        _ oper: GenericParser<StreamType, UserState, (Result, Result) -> Result>,\n        otherwise: Result\n    ) -> GenericParser {\n        \n        return chainLeft1(oper) <|> GenericParser(result: otherwise)\n        \n    }\n    \n    /// Return a parser that parses _one_ or more occurrences of `self`,\n    /// separated by oper`. Returns a value obtained by a _left_ associative\n    /// application of all functions returned by `oper` to the values returned\n    /// by `self`. This parser can for example be used to eliminate left\n    /// recursion which typically occurs in expression grammars.\n    ///\n    ///     let addOp: GenericParser<String, (), (Int, Int) -> Int> =\n    ///         StringParser.character(\"+\") *> GenericParser(result: +) <|>\n    ///         StringParser.character(\"-\") *> GenericParser(result: -)\n    ///\n    ///     let expr = number.chainLeft1(addOp)\n    ///\n    /// - parameter oper: The operator parser.\n    /// - returns: A parser that parses _one_ or more occurrences of `self`,\n    ///   separated by `oper`.\n    func chainLeft1(\n        _ oper: GenericParser<StreamType, UserState, (Result, Result) -> Result>\n    ) -> GenericParser {\n        \n        func rest(_ left: Result) -> GenericParser {\n            \n            let operParser = oper >>- { op in\n                \n                self >>- { right in rest(op(left, right)) }\n                \n            }\n            \n            return operParser <|> GenericParser(result: left)\n            \n        }\n        \n        return self >>- { result in rest(result) }\n        \n    }\n    \n    /// A parser that only succeeds when parser `self` fails. This parser does\n    /// not consume any input. This parser can be used to implement the\n    /// 'longest match' rule. For example, when recognizing keywords (for\n    /// example `let`), we want to make sure that a keyword is not followed by a\n    /// legal identifier character, in which case the keyword is actually an\n    /// identifier (for example `lets`). We can program this behaviour as\n    /// follows:\n    ///\n    ///     let alphaNum = StringParser.alphaNumeric\n    ///     let keyworkLet = StringParser.string(\"let\") <* alphaNum.noOccurence\n    var noOccurence: GenericParser<StreamType, UserState, ()> {\n        \n        let selfAttempt = attempt >>- { result in\n            \n            GenericParser<StreamType, UserState, ()>.unexpected(\n                String(reflecting: result)\n            )\n            \n        }\n        \n        return (selfAttempt <|> GenericParser<StreamType, UserState, ()>(\n            result: ())).attempt\n        \n    }\n    \n    /// Return a parser that applies parser `self` _zero_ or more times until\n    /// parser `end` succeeds. Returns the list of values returned by `self`.\n    /// This parser can be used to scan comments:\n    ///\n    ///     let anyChar = StringParser.anyCharacter\n    ///     let start = StringParser.string(\"<!--\")\n    ///     let end = StringParser.string(\"-->\")\n    ///     let comment = start *> anyChar.manyTill(end.attempt)\n    ///\n    /// Note the overlapping parsers `anyChar` and `end`, and therefore the use\n    /// of the 'attempt' combinator.\n    ///\n    /// - parameter end: End parser.\n    /// - returns: A parser that applies parser `self` _zero_ or more times\n    ///   until parser `end` succeeds.\n    func manyTill<End>(\n        _ end: GenericParser<StreamType, UserState, End>\n    ) -> GenericParser<StreamType, UserState, [Result]> {\n        \n        func scan() -> GenericParser<StreamType, UserState, [Result]> {\n            \n            let empty = end *>\n                GenericParser<StreamType, UserState, [Result]>(result: [])\n            \n            return empty <|> (self >>- { result in\n                \n                scan() >>- { results in\n                    \n                    let rs = results.prepending(result)\n                    return GenericParser<StreamType, UserState, [Result]>(\n                        result: rs\n                    )\n                    \n                }\n                \n            })\n            \n        }\n        \n        return scan()\n        \n    }\n    \n    /// Return a recursive parser combined with itself. It can be used to parse\n    /// nested expressions. As an exemple, an expression inside a pair of\n    /// parentheses is itself an expression that can be nested inside another\n    /// pair of parentheses.\n    ///\n    ///     let expression = GenericParser<...>.recursive { expression in\n    ///         parentheses(expression) <|>\n    ///         identifier <|>\n    ///         legalOperator <|> ...\n    ///\n    /// - parameter combine: A function receiving a placeholder parser as\n    ///   parameter that can be nested in other expressions.\n    /// - returns: A recursive parser combined with itself.\n    static func recursive(\n        _ combine: (GenericParser) -> GenericParser\n    ) -> GenericParser {\n        \n        var expression: GenericParser!\n        let placeholder = GenericParser { expression }\n        \n        expression = combine(placeholder)\n        \n        return expression\n        \n    }\n    \n}\n\n//==============================================================================\n// Extension containing methods related to special parsers.\npublic extension Parsec where StreamType.Iterator.Element == Result {\n    \n    /// A parser that accepts any kind of token. It is for example used to\n    /// implement 'eof'. It returns the accepted token.\n    static var anyToken: GenericParser<StreamType, UserState, Result> {\n        \n        return GenericParser.tokenPrimitive(\n            tokenDescription: { String(reflecting: $0) },\n            nextPosition: { pos, _ in pos },\n            match: { $0 })\n        \n    }\n    \n    /// A parser that only succeeds at the end of the input. This is not a\n    /// primitive parser but it is defined using `GenericParser.noOccurence`.\n    ///\n    /// - returns: A parser that only succeeds at the end of the input.\n    static var eof: GenericParser<StreamType, UserState, ()> {\n        \n        return GenericParser.anyToken.noOccurence <?>\n            LocalizedString(\"end of input\")\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/Configuration.swift",
    "content": "//==============================================================================\n// Configuration.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2016-05-27.\n// Copyright © 2016 David Dufresne. All rights reserved.\n//\n// Configuration of the parsers framework\n//==============================================================================\n\n//==============================================================================\n/// The `Configuration` type is used to customize the framework.\npublic struct Configuration {\n    \n    /// A hook to customize the localization of the strings contained in the\n    /// framework. The default function simply returns the `key` passed as\n    /// argument. A bundled application could use the sample\n    /// _Localizable.strings_ file as a starting point for its own strings\n    /// files and customize the framework this way:\n    ///\n    ///     Configuration.localizeString =\n    ///         { NSLocalizedString($0, comment: \"\") }\n    ///\n    public static var localizeString: (_ key: String) -> String = { $0 }\n    \n}\n\n//==============================================================================\n/// Function calling the string localization hook.\n///\n/// - parameters:\n///   - key: The key for a string in the default table.\nfunc LocalizedString(_ key: String) -> String {\n    \n    return Configuration.localizeString(key)\n\n}\n"
  },
  {
    "path": "Sources/SwiftParsec/Either.swift",
    "content": "//==============================================================================\n// Either.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2016-09-18.\n// Copyright © 2016 David Dufresne. All rights reserved.\n//\n// Either type\n//==============================================================================\n\n//==============================================================================\n/// The Either enumeration represents values with two possibilities: a value of\n/// type `Either<L, R>` is either `Left(L)` or `Right(R)`.\npublic enum Either<L, R> {\n    \n    /// Left posibility.\n    case left(L)\n    \n    /// Right posibility.\n    case right(R)\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/ExpressionParser.swift",
    "content": "//==============================================================================\n// Expression.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-23.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// A helper module to parse \"expressions\". Builds a parser given a table of\n// operators and associativities.\n//==============================================================================\n\n//==============================================================================\n/// This enumeration specifies the associativity of operators: right, left or\n/// none.\npublic enum Associativity {\n    \n    /// Right associative\n    case right\n    \n    /// Left associative\n    case left\n    \n    /// No associativity\n    case none\n    \n}\n\n//==============================================================================\n/// This data type specifies operators that work on values of type `Result`. An\n/// operator is either binary infix or unary prefix or postfix. A binary\n/// operator has also an associated associativity.\npublic enum Operator<StreamType: Stream, UserState, Result> {\n    \n    /// Infix operator and associativity.\n    case infix(\n        GenericParser<StreamType, UserState, (Result, Result) -> Result>,\n        Associativity\n    )\n    \n    /// Prefix operator.\n    case prefix(GenericParser<StreamType, UserState, (Result) -> Result>)\n    \n    /// Postfix operator.\n    case postfix(GenericParser<StreamType, UserState, (Result) -> Result>)\n    \n}\n\n//==============================================================================\n/// Represents a table of  operators. The `makeExpressionParser()` method is\n/// used to create parsers based on the table.\npublic struct OperatorTable<StreamType: Stream, UserState, Result>:\nRangeReplaceableCollection, ExpressibleByArrayLiteral {\n    \n    /// Represents a valid position in the operator table.\n    public typealias Index = Int\n    \n    /// Operator table's generator.\n    public typealias Iterator = IndexingIterator<OperatorTable>\n    \n    /// Element type of the operator table.\n    public typealias Element = [Operator<StreamType, UserState, Result>]\n    \n    /// The position of the first element.\n    public let startIndex = 0\n    \n    /// The operator table's \"past the end\" position.\n    public var endIndex: Int { return table.count }\n    \n    // Backing store.\n    private var table: [Element]\n    \n    /// Create an instance initialized with elements.\n    ///\n    /// - parameter arrayLiteral: Arrays of `Operator`.\n    public init(arrayLiteral elements: Element...) {\n        \n        table = elements\n        \n    }\n    \n    /// Create an empty instance.\n    public init() { table = [] }\n    \n    /// Returns the position immediately after i.\n    ///\n    /// - SeeAlso: `IndexableBase` protocol.\n    public func index(after i: OperatorTable.Index) -> OperatorTable.Index {\n        \n        return table.index(after: i)\n        \n    }\n    \n    /// Build an expression parser for terms returned by `combined` with\n    /// operators from `self`, taking the associativity and precedence specified\n    /// in `self` into account. Prefix and postfix operators of the same\n    /// precedence can only occur once (i.e. `--2` is not allowed if `-` is\n    /// prefix negate). Prefix and postfix operators of the same precedence\n    /// associate to the left (i.e. if `++` is postfix increment, than `-2++`\n    /// equals `-1`, not `-3`).\n    ///\n    /// It takes care of all the complexity involved in building expression\n    /// parser. Here is an example of an expression parser that handles prefix\n    /// signs, postfix increment and basic arithmetic:\n    ///\n    ///     func binary(\n    ///         name: String,\n    ///         function: (Int, Int) -> Int,\n    ///         assoc: Associativity\n    ///     ) -> Operator<String, (), Int> {\n    ///\n    ///         let opParser = StringParser.string(name) *>\n    ///             GenericParser(result: function)\n    ///\n    ///         return .Infix(opParser, assoc)\n    ///\n    ///     }\n    ///\n    ///     func prefix(\n    ///         name: String,\n    ///         function: Int -> Int\n    ///     ) -> Operator<String, (), Int> {\n    ///\n    ///         let opParser = StringParser.string(name) *>\n    ///             GenericParser(result: function)\n    ///\n    ///         return .Prefix(opParser)\n    ///\n    ///     }\n    ///\n    ///     func postfix(\n    ///         name: String,\n    ///         function: Int -> Int\n    ///     ) -> Operator<String, (), Int> {\n    ///\n    ///         let opParser = StringParser.string(name) *>\n    ///             GenericParser(result: function)\n    ///\n    ///         return .Postfix(opParser.attempt)\n    ///\n    ///     }\n    ///\n    ///     let opTable: OperatorTable<String, (), Int> = [\n    ///\n    ///         [\n    ///             prefix(\"-\", function: -),\n    ///             prefix(\"+\", function: { $0 })\n    ///         ],\n    ///         [\n    ///             binary(\"^\", function: power, assoc: .right)\n    ///         ],\n    ///         [\n    ///             binary(\"*\", function: *, assoc: .left),\n    ///             binary(\"/\", function: /, assoc: .left)\n    ///         ],\n    ///         [\n    ///             binary(\"+\", function: +, assoc: .left),\n    ///             binary(\"-\", function: -, assoc: .left)\n    ///         ]\n    ///\n    ///     ]\n    ///\n    ///     let openingParen = StringParser.character(\"(\")\n    ///     let closingParen = StringParser.character(\")\")\n    ///     let decimal = GenericTokenParser<()>.decimal\n    ///\n    ///     let expression = opTable.makeExpressionParser { expression in\n    ///\n    ///         expression.between(openingParen, closingParen) <|>\n    ///             decimal <?> \"simple expression\"\n    ///\n    ///     } <?> \"expression\"\n    ///\n    /// - parameters:\n    ///   - combine: A function receiving a 'simple expression' as\n    ///     parameter that can be nested in other expressions.\n    ///   - expression: A parser that can be combined with other expressions.\n    /// - returns: An expression parser for terms returned by `combined`\n    ///   with operators from `self`.\n    /// - SeeAlso:\n    ///   `GenericParser.recursive(\n    ///       combine: GenericParser -> GenericParser\n    ///   ) -> GenericParser\n    public func makeExpressionParser(\n        _ combine: (\n            _ expression: GenericParser<StreamType, UserState, Result>\n        ) -> GenericParser<StreamType, UserState, Result>\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        var term: GenericParser<StreamType, UserState, Result>!\n        let lazyTerm = GenericParser<StreamType, UserState, Result> { term }\n        \n        let expr = reduce(lazyTerm) { buildParser($0, operators: $1) }\n        term = combine(expr)\n        \n        return expr\n        \n    }\n    \n    private typealias InfixOperatorParser =\n        GenericParser<StreamType, UserState, (Result, Result) -> Result>\n    private typealias PrefixOperatorParser =\n        GenericParser<StreamType, UserState, (Result) -> Result>\n    private typealias PostfixOperatorParser =\n        GenericParser<StreamType, UserState, (Result) -> Result>\n    \n    private typealias OperatorsTuple = (\n        right: [InfixOperatorParser],\n        left: [InfixOperatorParser],\n        none: [InfixOperatorParser],\n        prefix: [PrefixOperatorParser],\n        postfix: [PostfixOperatorParser]\n    )\n    \n    private func buildParser(\n        _ term: GenericParser<StreamType, UserState, Result>,\n        operators: [Operator<StreamType, UserState, Result>]\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        let ops: OperatorsTuple = operators.reduce(\n            ([], [], [], [], []),\n            splitOperators\n        )\n        \n        let rightAssocOp = GenericParser.choice(ops.right)\n        let leftAssocOp = GenericParser.choice(ops.left)\n        let nonAssocOp = GenericParser.choice(ops.none)\n        let prefixOp = GenericParser.choice(ops.prefix)\n        let postfixOp = GenericParser.choice(ops.postfix)\n        \n        let rightAssocMsg = LocalizedString(\"right\")\n        let ambigiousRight = ambigious(rightAssocOp, assoc: rightAssocMsg)\n        \n        let leftAssocMsg = LocalizedString(\"left\")\n        let ambigiousLeft = ambigious(leftAssocOp, assoc: leftAssocMsg)\n        \n        let nonAssocMsg = LocalizedString(\"non\")\n        let ambigiousNon = ambigious(rightAssocOp, assoc: nonAssocMsg)\n        \n        let prefixParser = prefixOp <|> GenericParser(result: { $0 })\n        let postfixParser = postfixOp <|> GenericParser(result: { $0 })\n        \n        let termParser = prefixParser >>- { pre in\n            \n            term >>- { t in\n                \n                postfixParser >>- { post in\n                    \n                    GenericParser(result: post(pre(t)))\n                    \n                }\n                \n            }\n            \n        }\n        \n        func rightAssocParser(\n            _ left: Result\n        ) -> GenericParser<StreamType, UserState, Result> {\n            \n            let rightTerm = termParser >>- { rightAssocParser1($0) }\n            \n            let apply = rightAssocOp >>- { f in\n                \n                rightTerm >>- { right in GenericParser(result: f(left, right)) }\n                \n            }\n            \n            return apply <|> ambigiousLeft <|> ambigiousNon\n            \n        }\n        \n        func rightAssocParser1(\n            _ right: Result\n        ) -> GenericParser<StreamType, UserState, Result> {\n            \n            return rightAssocParser(right) <|> GenericParser(result: right)\n            \n        }\n        \n        func leftAssocParser(\n            _ left: Result\n        ) -> GenericParser<StreamType, UserState, Result> {\n            \n            let apply = leftAssocOp >>- { f in\n                \n                termParser >>- { right in\n                    \n                    leftAssocParser1(f(left, right))\n                \n                }\n                \n            }\n            \n            return apply <|> ambigiousRight <|> ambigiousNon\n                \n        }\n        \n        func leftAssocParser1(\n            _ right: Result\n        ) -> GenericParser<StreamType, UserState, Result> {\n            \n            return leftAssocParser(right) <|> GenericParser(result: right)\n            \n        }\n        \n        func nonAssocParser(\n            _ left: Result\n        ) -> GenericParser<StreamType, UserState, Result> {\n            \n            return nonAssocOp >>- { f in\n                \n                termParser >>- { right in\n                    \n                    ambigiousRight <|> ambigiousLeft <|> ambigiousNon <|>\n                        GenericParser(result: f(left, right))\n                    \n                }\n                \n            }\n            \n        }\n        \n        return termParser >>- { t in\n            \n            rightAssocParser(t) <|> leftAssocParser(t) <|> nonAssocParser(t) <|>\n                GenericParser(result: t) <?> LocalizedString(\"operator\")\n            \n        }\n        \n    }\n    \n    private func splitOperators(\n        operators: OperatorsTuple,\n        op: Operator<StreamType, UserState, Result>\n    ) -> OperatorsTuple {\n        \n        var ops = operators\n        \n        switch op {\n            \n        case .infix(let parser, let assoc):\n            \n            switch assoc {\n                \n            case .none:\n                \n                var n = ops.none\n                n.append(parser)\n                \n                ops.none = n\n                \n            case .left:\n                \n                var l = ops.left\n                l.append(parser)\n                \n                ops.left = l\n                \n            case .right:\n                \n                var r = ops.right\n                r.append(parser)\n                \n                ops.right = r\n                \n            }\n            \n        case .prefix(let parser):\n            \n            var pre = ops.prefix\n            pre.append(parser)\n            \n            ops.prefix = pre\n            \n        case .postfix(let parser):\n            \n            var post = ops.postfix\n            post.append(parser)\n            \n            ops.postfix = post\n            \n        }\n        \n        return ops\n        \n    }\n    \n    private func ambigious(\n        _ op: InfixOperatorParser,\n        assoc: String\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        #if _runtime(_ObjC)\n        \n        let msg = LocalizedString(\"ambiguous use of a %@ associative operator\")\n        let localizedMsg = String.localizedStringWithFormat(msg, assoc as CVarArg)\n        \n        #else\n        \n        // https://bugs.swift.org/browse/SR-957\n        let localizedMsg = LocalizedString(\"ambiguous use of a \\(assoc) associative operator\")\n        \n        #endif\n        \n        return (op *> GenericParser.fail(localizedMsg)).attempt\n        \n    }\n    \n    /// Replace the given subRange of elements with newElements.\n    ///\n    /// - parameters:\n    ///   - subRange: Range of elements to replace.\n    ///   - newElements: New elements replacing the previous elements contained\n    ///     in `subRange`.\n    public mutating func replaceSubrange<C: Collection>(\n        _ subrange: Range<Index>, with newElements: C\n    ) where C.Iterator.Element == Iterator.Element {\n        \n        table.replaceSubrange(subrange, with: newElements)\n        \n    }\n    \n    public subscript(position: Index) -> Element { return table[position] }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/GenericParser.swift",
    "content": "//==============================================================================\n// Primitive.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-04.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// The primitive parser combinators.\n//==============================================================================\n\n//==============================================================================\n/// `GenericParser` is a generic implementation of the `Parsec`.\n///\n/// - requires: StreamType.Iterator has to be a value type.\npublic final class GenericParser<StreamType: Stream, UserState, Result>:\nParsec {\n    \n    /// Create a parser containing the injected result.\n    ///\n    /// - parameter result: The result to inject into the parser.\n    public init(result: Result) {\n        \n        parse = { state in\n            \n            .none(.ok(result, state,\n                      ParseError.unknownParseError(state.position)))\n            \n        }\n        \n    }\n    \n    /// Create a parser containing a function that return a parser. Used to\n    /// execute functions lazily.\n    ///\n    /// - parameter function: The function to execute when the parser is run.\n    public init(function: @escaping () -> GenericParser) {\n        \n        parse = { state in\n            \n            return function().parse(state)\n            \n        }\n        \n    }\n    \n    /// Create an instance with the given parse function.\n    init(\n        parse: @escaping (\n            ParserState<StreamType.Iterator, UserState>\n        ) -> Consumed<StreamType, UserState, Result>\n    ) {\n        \n        self.parse = parse\n        \n    }\n    \n    /// The function executed when the parser is run.\n    ///\n    /// - Parameter state: The state of the parser.\n    /// - returns: The result of the parsing.\n    let parse: (_ state: ParserState<StreamType.Iterator, UserState>)\n    -> Consumed<StreamType, UserState, Result>\n    \n    /// Return a parser containing the result of mapping transform over `self`.\n    ///\n    /// This method has the synonym infix operator `<^>`.\n    ///\n    /// - parameter transform: A mapping function.\n    /// - returns: A new parser with the mapped content.\n    public func map<T>(\n        _ transform: @escaping (Result) -> T\n    ) -> GenericParser<StreamType, UserState, T> {\n        \n        return GenericParser<StreamType, UserState, T>(parse: { state in\n            \n            let consumed = self.parse(state)\n            return consumed.map(transform)\n            \n        })\n        \n    }\n    \n    /// Return a parser by applying the function contained in the supplied\n    /// parser to self.\n    ///\n    /// This method has the synonym infix operator `<*>`.\n    ///\n    /// - parameter parser: The parser containing the function to apply to self.\n    /// - returns: A parser with the applied function.\n    public func apply<T>(\n        _ parser: GenericParser<StreamType, UserState, (Result) -> T>\n    ) -> GenericParser<StreamType, UserState, T> {\n        \n        return parser >>- { f in self.map(f) }\n        \n    }\n    \n    /// This combinator implements choice. The parser `p.alternative(q)` first\n    /// applies `p`. If it succeeds, the value of `p` is returned. If `p` fails\n    /// _without consuming any input_, parser `q` is tried. The parser is called\n    /// _predictive_ since `q` is only tried when parser `p` didn't consume any\n    /// input (i.e.. the look ahead is 1). This non-backtracking behaviour\n    /// allows for both an efficient implementation of the parser combinators\n    /// and the generation of good error messages.\n    ///\n    /// This method has the synonym infix operator `<|>`.\n    ///\n    /// - parameter altParser: The alternative parser to try if `self` fails.\n    /// - returns: A parser that will first try `self`. If it consumed no input,\n    ///   it will try `altParser`.\n    public func alternative(_ altParser: GenericParser) -> GenericParser {\n        \n        return GenericParser(parse: { state in\n            \n            let consumed = self.parse(state)\n            guard case .none(let reply) = consumed,\n                case .error(let error) = reply else {\n                \n                return consumed\n                \n            }\n            \n            let altConsumed = altParser.parse(state)\n            switch altConsumed {\n                \n            case .some: return altConsumed\n                \n            case .none(let reply):\n                \n                return .none(reply.mergeParseError(error))\n                \n            }\n            \n        })\n        \n    }\n    \n    /// Return a parser containing the result of mapping transform over `self`.\n    ///\n    /// This method has the synonym infix operator `>>-` (bind).\n    ///\n    /// - parameter transform: A mapping function returning a parser.\n    /// - returns: A new parser with the mapped content.\n    public func flatMap<T>(\n        _ transform: @escaping (\n            Result\n        ) -> GenericParser<StreamType, UserState, T>\n    ) -> GenericParser<StreamType, UserState, T> {\n        \n        func runRightParser(\n            _ constructor: (\n                ParserReply<StreamType, UserState, T>\n            ) -> Consumed<StreamType, UserState, T>,\n            result: Result,\n            state: ParserState<StreamType.Iterator, UserState>,\n            error: ParseError\n        ) -> Consumed<StreamType, UserState, T> {\n            \n            let parser = transform(result)\n            \n            let consumed = parser.parse(state)\n            switch consumed {\n                \n            // If parser consumes, return the result right away.\n            case .some: return consumed\n                \n            case .none(let reply):\n                \n                // If the left parser consumes and the right parser doesn't\n                // consume input, but is okay, we return that it successfully\n                // consumed some input. But if the left and right parser didn't\n                // consume we return that it successfully didn't consumed some\n                // input.\n                //\n                // If the left parser consumes and the right parser doesn't\n                // consume input, but errors, we return that it failed while\n                // consuming some input. But if the left and right parser didn't\n                // consume we return that it failed while not consuming any\n                // input.\n                return constructor(reply.mergeParseError(error))\n                \n            }\n            \n        }\n        \n        func consumed(\n            _ constructor: (\n                ParserReply<StreamType, UserState, T>\n            ) -> Consumed<StreamType, UserState, T>,\n            reply: ParserReply<StreamType, UserState, Result>\n        ) -> Consumed<StreamType, UserState, T> {\n            \n            switch reply {\n                \n            case .ok(let result, let state, let error):\n                \n                return runRightParser(constructor, result: result, state: state,\n                                      error: error)\n                \n            case .error(let error):\n                \n                return constructor(.error(error))\n                \n            }\n            \n        }\n        \n        return GenericParser<StreamType, UserState, T>(parse: { state in\n            \n            switch self.parse(state) {\n                \n            case .some(let reply):\n                \n                return consumed(Consumed.some, reply: reply)\n                \n            case .none(let reply):\n                \n                return consumed(Consumed.none, reply: reply)\n                \n            }\n            \n        })\n        \n    }\n    \n    /// This combinator is used whenever arbitrary look ahead is needed. Since\n    /// it pretends that it hasn't consumed any input when `self` fails, the\n    /// ('<|>') combinator will try its second alternative even when the first\n    /// parser failed while consuming input.\n    ///\n    /// The `attempt` combinator can for example be used to distinguish\n    /// identifiers and reserved words. Both reserved words and identifiers are\n    /// a sequence of letters. Whenever we expect a certain reserved word where\n    /// we can also expect an identifier we have to use the `attempt`\n    /// combinator. Suppose we write:\n    ///\n    ///     let letExpr = StringParser.string(\"let\")\n    ///     let identifier = letter.many1\n    ///\n    ///     let expr = letExpr <|> identifier <?> \"expression\"\n    ///\n    /// If the user writes \\\"lexical\\\", the parser fails with: _unexpected 'x',\n    /// expecting 't' in \"let\"_. Indeed, since the ('<|>') combinator only tries\n    /// alternatives when the first alternative hasn't consumed input, the\n    /// `identifier` parser is never tried (because the prefix \"le\" of the\n    /// `string(\"let\")` parser is already consumed). The right behaviour can be\n    /// obtained by adding the `attempt` combinator:\n    ///\n    ///     let letExpr = StringParser.string(\"let\")\n    ///     let identifier = StringParser.letter.many1\n    ///\n    ///     let expr = letExpr.attempt <|> identifier <?> \"expression\"\n    ///\n    /// - returns: A parser that pretends that it hasn't consumed any input when\n    ///   `self` fails.\n    public var attempt: GenericParser {\n        \n        return GenericParser(parse: { state in\n            \n            let consumed = self.parse(state)\n            if case .some(let reply) = consumed, case .error = reply {\n                \n                return .none(reply)\n                \n            }\n            \n            return consumed\n            \n        })\n        \n    }\n    \n    /// A combinator that parses without consuming any input.\n    ///\n    /// If `self` fails and consumes some input, so does `lookAhead`. Combine\n    /// with `attempt` if this is undesirable.\n    ///\n    /// - returns: A parser that parses without consuming any input.\n    public var lookAhead: GenericParser {\n        \n        return GenericParser(parse: { state in\n            \n            let consumed = self.parse(state)\n            \n            if case .some(let reply) = consumed,\n            case .ok(let result, _, _) = reply {\n                \n                return .none(\n                    .ok(result,\n                        state,\n                        ParseError.unknownParseError(state.position)\n                    )\n                )\n                \n            }\n            \n            return consumed\n            \n        })\n        \n    }\n    \n    /// The `many` combinator applies the parser `self` _zero_ or more times. It\n    /// returns an array of the returned values of `self`.\n    ///\n    ///     let identifier = identifierStart >>- { char in\n    ///\n    ///         identifierLetter.many >>- { (var chars) in\n    ///\n    ///             chars.insert(char, at: 0)\n    ///             return GenericParser(result: String(chars))\n    ///\n    ///         }\n    ///\n    ///     }\n    public var many: GenericParser<StreamType, UserState, [Result]> {\n        \n        return manyAccumulator { (result, results) in\n            \n            return results.appending(result)\n            \n        }\n        \n    }\n    \n    /// The `skipMany` combinator applies the parser `self` _zero_ or more\n    /// times, skipping its result.\n    ///\n    ///     let spaces = space.skipMany\n    ///\n    /// - returns: An parser with an empty result.\n    public var skipMany: GenericParser<StreamType, UserState, ()> {\n        \n        let manyAcc = manyAccumulator { (_, accum: [Result]) in accum }\n        return manyAcc.map { _ in () }\n        \n    }\n    \n    /// This combinator applies `self` _zero_ or more times. It returns an\n    /// accumulation of the returned values of `self` that were passed to the\n    /// `accumulator` function.\n    ///\n    /// - parameter accumulator: An accumulator function that process the value\n    ///   returned by `self`. The first argument is the value returned by `self`\n    ///   and the second argument is the previous processed values returned by\n    ///   this accumulator function. It returns the result of processing the\n    ///   passed value and the accumulated values.\n    /// - returns: The processed values of the accumulator function.\n    public func manyAccumulator<Accumulator: EmptyInitializable>(\n        _ accumulator: @escaping (Result, Accumulator) -> Accumulator\n    ) -> GenericParser<StreamType, UserState, Accumulator> {\n        \n        return GenericParser<StreamType, UserState, Accumulator>(parse:\n        { initState in\n            \n            var results = Accumulator()\n            var newState = initState\n            \n            var hasConsumed = false\n            \n            repeat {\n                \n                let consumed = self.parse(newState)\n                switch consumed {\n                    \n                case .some(let reply):\n                    \n                    switch reply {\n                        \n                    case .ok(let result, let state, _):\n                        \n                        results = accumulator(result, results)\n                        newState = state\n                        \n                    case .error(let error):\n                        \n                        return .some(.error(error))\n                        \n                    }\n                    \n                case .none(let reply):\n                    \n                    switch reply {\n                        \n                    case .ok:\n            \n                        let failureMsg = LocalizedString(\"Combinator 'many' is applied to a parser that accepts an empty string.\")\n                        assertionFailure(failureMsg)\n                        \n                    case .error(let error):\n                        \n                        if hasConsumed {\n                            \n                            return .some(.ok(results, newState, error))\n                            \n                        }\n            \n                        return .none(.ok(results, newState, error))\n                        \n                    }\n            \n                }\n                \n                hasConsumed = true\n                \n            } while true // Loop while the parser consumes.\n            \n        })\n        \n    }\n    \n    /// A parser that always fails without consuming any input.\n    public static var empty: GenericParser {\n        \n        return GenericParser(parse: { state in\n            \n            let position = state.position\n            return .none(.error(ParseError.unknownParseError(position)))\n            \n        })\n        \n    }\n    \n    /// The parser returned by `p.labels(message)` behaves as parser `p`, but\n    /// whenever the parser `p` fails _without consuming any input_, it replaces\n    /// expected error messages with the expected error message `message`.\n    ///\n    /// This is normally used at the end of a set alternatives where we want to\n    /// return an error message in terms of a higher level construct rather than\n    /// returning all possible characters. For example, if the `expr` parser\n    /// from the `attempt` example would fail, the error message is: '...:\n    /// expecting expression'. Without the `GenericParser.labels()` combinator,\n    /// the message would be like '...: expecting \"let\" or \"letter\"', which is\n    /// less friendly.\n    ///\n    /// This method has the synonym infix operator `<?>`.\n    ///\n    /// - parameter message: The new error message.\n    /// - returns: A parser with a replaced error message.\n    public func labels(_ messages: String...) -> GenericParser {\n        \n        return GenericParser(parse: { state in\n            \n            let consumed = self.parse(state)\n            switch consumed {\n                \n            case .some: return consumed\n                \n            case .none(let reply):\n                \n                switch reply {\n                    \n                case .ok(let result, let state, var error):\n                    \n                    if !error.isUnknown {\n                        \n                        error.insertLabelsAsExpected(messages)\n                        \n                    }\n                    \n                    return .none(.ok(result, state, error))\n                    \n                case .error(var error):\n                    \n                    error.insertLabelsAsExpected(messages)\n                    return .none(.error(error))\n                    \n                }\n                \n            }\n            \n        })\n        \n    }\n    \n    /// Return a parser that always fails with an unexpected error message\n    /// without consuming any input.\n    ///\n    /// The parsers 'fail', '\\<?\\>' and `unexpected` are the three parsers used\n    /// to generate error messages. Of these, only '<?>' is commonly used. For\n    /// an example of the use of `unexpected`, see the definition of\n    /// `GenericParser.noOccurence`.\n    ///\n    /// - parameter message: The error message.\n    /// - returns: A parser that always fails with an unexpected error message\n    ///   without consuming any input.\n    /// - SeeAlso: `GenericParser.noOccurence`,\n    ///   `GenericParser.fail(message: String)` and `<?>`\n    public static func unexpected(_ message: String) -> GenericParser {\n        \n        return GenericParser { state in\n\n            .none(\n                .error(\n                    ParseError(\n                        position: state.position,\n                        messages: [.unexpected(message)]\n                    )\n                )\n            )\n            \n        }\n        \n    }\n    \n    /// Return a parser that always fail with the supplied message.\n    ///\n    /// - parameter message: The failure message.\n    /// - returns: A parser that always fail.\n    public static func fail(_ message: String) -> GenericParser {\n        \n        return GenericParser(parse: { state in\n            \n            let position = state.position\n            let error = ParseError(\n                position: position,\n                messages: [.generic(message)]\n            )\n            \n            return .none(.error(error))\n            \n        })\n        \n    }\n    \n    /// Return the current source position.\n    ///\n    /// - returns: The current source position.\n    /// - SeeAlso 'SourcePosition'.\n    public static var\n    sourcePosition: GenericParser<StreamType, UserState, SourcePosition> {\n        \n        return GenericParser<StreamType, UserState, SourcePosition>(parse:\n        { state in\n            \n            return .none(.ok(state.position, state,\n                             ParseError.unknownParseError(state.position)))\n            \n        })\n        \n    }\n    \n    /// Return a parser that applies the result of the supplied parsers to the\n    /// lifted function. The parsers are applied from left to right.\n    ///\n    /// - parameters:\n    ///   - function: The Binary function to lift into the parser.\n    ///   - parser1: The parser returning the first argument passed to the\n    ///     lifted function.\n    ///   - parser2: The parser returning the second argument passed to the\n    ///     lifted function.\n    /// - returns: A parser that applies the result of the supplied parsers to\n    ///   the lifted function.\n    public static func lift2<Param1, Param2>(\n        _ function: @escaping (Param1, Param2) -> Result,\n        parser1: GenericParser<StreamType, UserState, Param1>,\n        parser2: GenericParser<StreamType, UserState, Param2>\n    ) -> GenericParser {\n        \n        return parser1 >>- { result1 in\n            \n            parser2 >>- { result2 in\n                \n                let combinedResult = function(result1, result2)\n                return GenericParser(result: combinedResult)\n                \n            }\n            \n        }\n        \n    }\n    \n    /// Return a parser that applies the result of the supplied parsers to the\n    /// lifted function. The parsers are applied from left to right.\n    ///\n    /// - parameters:\n    ///   - function: The Ternary function to lift into the parser.\n    ///   - parser1: The parser returning the first argument passed to the\n    ///     lifted function.\n    ///   - parser2: The parser returning the second argument passed to the\n    ///     lifted function.\n    ///   - parser3: The parser returning the third argument passed to the\n    ///     lifted function.\n    /// - returns: A parser that applies the result of the supplied parsers to\n    ///   the lifted function.\n    public static func lift3<Param1, Param2, Param3>(\n        _ function: @escaping (Param1, Param2, Param3) -> Result,\n        parser1: GenericParser<StreamType, UserState, Param1>,\n        parser2: GenericParser<StreamType, UserState, Param2>,\n        parser3: GenericParser<StreamType, UserState, Param3>\n    ) -> GenericParser {\n        \n        return parser1 >>- { result1 in\n            \n            parser2 >>- { result2 in\n                \n                parser3 >>- { result3 in\n                    \n                    let combinedResult = function(result1, result2, result3)\n                    return GenericParser(result: combinedResult)\n                    \n                }\n\n            }\n            \n        }\n\n    }\n    \n    /// Return a parser that applies the result of the supplied parsers to the\n    /// lifted function. The parsers are applied from left to right.\n    ///\n    /// - parameters:\n    ///   - function: The function to lift into the parser.\n    ///   - parser1: The parser returning the first argument passed to the\n    ///     lifted function.\n    ///   - parser2: The parser returning the second argument passed to the\n    ///     lifted function.\n    ///   - parser3: The parser returning the third argument passed to the\n    ///     lifted function.\n    ///   - parser4: The parser returning the fourth argument passed to the\n    ///     lifted function.\n    /// - returns: A parser that applies the result of the supplied parsers to\n    ///   the lifted function.\n    public static func lift4<Param1, Param2, Param3, Param4>(\n        _ function: @escaping (Param1, Param2, Param3, Param4) -> Result,\n        parser1: GenericParser<StreamType, UserState, Param1>,\n        parser2: GenericParser<StreamType, UserState, Param2>,\n        parser3: GenericParser<StreamType, UserState, Param3>,\n        parser4: GenericParser<StreamType, UserState, Param4>\n    ) -> GenericParser {\n        \n        return parser1 >>- { result1 in\n            \n            parser2 >>- { result2 in\n                \n                parser3 >>- { result3 in\n                    \n                    parser4 >>- { result4 in\n                        \n                        let combinedResult = function(\n                            result1,\n                            result2,\n                            result3,\n                            result4\n                        )\n                        return GenericParser(result: combinedResult)\n                        \n                    }\n\n                }\n                \n            }\n            \n        }\n\n    }\n    \n    /// Return a parser that applies the result of the supplied parsers to the\n    /// lifted function. The parsers are applied from left to right.\n    ///\n    /// - parameters:\n    ///   - function: The function to lift into the parser.\n    ///   - parser1: The parser returning the first argument passed to the\n    ///     lifted function.\n    ///   - parser2: The parser returning the second argument passed to the\n    ///     lifted function.\n    ///   - parser3: The parser returning the third argument passed to the\n    ///     lifted function.\n    ///   - parser4: The parser returning the fourth argument passed to the\n    ///     lifted function.\n    ///   - parser5: The parser returning the fifth argument passed to the\n    ///     lifted function.\n    /// - returns: A parser that applies the result of the supplied parsers to\n    ///   the lifted function.\n    public static func lift5<Param1, Param2, Param3, Param4, Param5>(\n        _ function: @escaping (Param1, Param2, Param3, Param4, Param5) -> Result,\n        parser1: GenericParser<StreamType, UserState, Param1>,\n        parser2: GenericParser<StreamType, UserState, Param2>,\n        parser3: GenericParser<StreamType, UserState, Param3>,\n        parser4: GenericParser<StreamType, UserState, Param4>,\n        parser5: GenericParser<StreamType, UserState, Param5>\n    ) -> GenericParser {\n        \n        return parser1 >>- { result1 in\n            \n            parser2 >>- { result2 in\n                \n                parser3 >>- { result3 in\n                    \n                    parser4 >>- { result4 in\n                        \n                        parser5 >>- { result5 in\n                            \n                            let combinedResult = function(\n                                result1,\n                                result2,\n                                result3,\n                                result4,\n                                result5\n                            )\n                            return GenericParser(result: combinedResult)\n                            \n                        }\n                        \n                    }\n                    \n                }\n                \n            }\n            \n        }\n\n    }\n    \n    /// Return the user state.\n    ///\n    /// - returns: The user state\n    static public var\n    userState: GenericParser<StreamType, UserState, UserState> {\n        \n        return GenericParser<StreamType, UserState, UserState>(parse: { state in\n            \n            return .none(.ok(state.userState, state,\n                             ParseError.unknownParseError(state.position)))\n            \n        })\n        \n    }\n\n    /// The `updateUserState` method applies the function `update` to the user\n    /// state. Suppose that we want to count identifiers in a source, we could\n    /// use the user state as:\n    ///\n    ///     let incrementCount = StringParser.updateUserState { ++$0 }\n    ///     let expr = identifier <* incrementCount\n    ///\n    /// - parameter update: The function applied to the `UserState`. It returns\n    ///   the updated `UserState`.\n    /// - returns: An empty parser that will update the `UserState`.\n    public static func updateUserState(\n        _ update: @escaping (UserState) -> UserState\n    ) -> GenericParser<StreamType, UserState, ()> {\n        \n        return GenericParser<StreamType, UserState, ()>(parse: { parserState in\n            \n            let userState = update(parserState.userState)\n            \n            var state = parserState\n            state.userState = userState\n            \n            let position = state.position\n            \n            return .none(.ok((), state, ParseError.unknownParseError(position)))\n            \n        })\n        \n    }\n    \n    /// Run the parser and return the result of the parsing if it succeeded.\n    /// If an error occured, it is returned. Contrary to the `run()` method, it\n    /// doesn't throw an exception.\n    ///\n    /// - parameters:\n    ///   - userState: The state supplied by the user.\n    ///   - sourceName: The name of the source (i.e. file name).\n    ///   - input: The input StreamType to parse.\n    /// - returns: The result of the parsing on success, otherwise the parse\n    ///   error.\n    public func runSafe(\n        userState: UserState,\n        sourceName: String,\n        input: StreamType\n    ) -> Either<ParseError, Result> {\n        \n        let position = SourcePosition(name: sourceName, line: 1, column: 1)\n        let state = ParserState(\n            input: input.makeIterator(),\n            position: position,\n            userState: userState\n        )\n        \n        let reply = parse(state).parserReply\n        switch reply {\n            \n        case .ok(let result, _, _):\n            \n            return .right(result)\n            \n        case .error(let error):\n            \n            return .left(error)\n            \n        }\n\n    }\n    \n}\n\n//==============================================================================\n// Parsec extension\npublic extension Parsec {\n    \n    // TODO: Move this function into the `Parsec` protocol extension when Swift\n    // will allow to add requirements to `associatedtype` type constraint\n    // (Ex.: `associatedtype StreamType: CollectionType\n    // where StreamType.SubSequence == Stream`)\n    \n    /// Return a parser that accepts a token `Element` with `Result` when the\n    /// function `match(Element) -> Result` returns\n    /// `Optional.SomeWrapped(Result)`. The token can be shown using\n    /// `tokenDescription(Element) -> String`. The position of the _next_ token\n    /// should be returned when\n    /// `nextPosition(SourcePosition, Element, StreamType) -> SourcePosition`\n    /// is called with the current source position, the current token and the\n    /// rest of the tokens.\n    ///\n    /// This is the most primitive combinator for accepting tokens. For example,\n    /// the `GenericParser.character()` parser could be implemented as:\n    ///\n    ///     public static func character(\n    ///         char: Character\n    ///     ) -> GenericParser<StreamType, UserState, Result> {\n    ///\n    ///         return tokenPrimitive(\n    ///             tokenDescription: { \"\\\"\" + $0 + \"\\\"\" },\n    ///             nextPosition: { (var position, elem, _) in\n    ///\n    ///                 position.updatePosition(elem)\n    ///                 return position\n    ///\n    ///             },\n    ///             match: { elem in\n    ///\n    ///                 char == elem ? elem : nil\n    ///\n    ///             })\n    ///\n    ///     }\n    ///\n    /// - parameters:\n    ///   - tokenDescription: A function to describe the token.\n    ///   - nextPosition: A function returning the position of the next token.\n    ///   - match: A function returning an optional result when the token match\n    ///     a predicate.\n    /// - returns: Return a parser that accepts a token `Element` with result\n    ///   `Result` when the token matches.\n    static func tokenPrimitive(\n        tokenDescription: @escaping (StreamType.Iterator.Element) -> String,\n        nextPosition: @escaping (\n            SourcePosition, StreamType.Iterator.Element\n        ) -> SourcePosition,\n        match: @escaping (StreamType.Iterator.Element) -> Result?\n    ) -> GenericParser<StreamType, UserState, Result> {\n        \n        return GenericParser(parse: { state in\n            \n            var input = state.input\n            let position = state.position\n            \n            guard let tok = input.next() else {\n                \n                let error =\n                    ParseError.unexpectedParseError(position, message: \"\")\n                return .none(.error(error))\n                \n            }\n            \n            guard let result = match(tok) else {\n                \n                let error = ParseError.unexpectedParseError(\n                    position,\n                    message: tokenDescription(tok)\n                )\n                return .none(.error(error))\n                \n            }\n            \n            let newPosition = nextPosition(position, tok)\n            let newState = ParserState(\n                input: input,\n                position: newPosition,\n                userState: state.userState\n            )\n            let unknownError = ParseError.unknownParseError(newPosition)\n            \n            return .some(.ok(result, newState, unknownError))\n            \n        })\n        \n    }\n    \n}\n\n//==============================================================================\n// Parsec extension where the elements are `Equatable`\npublic extension Parsec\nwhere StreamType.Iterator.Element: Equatable {\n    \n    // TODO: Move this function into the `Parsec` protocol extension when Swift\n    // will allow to add requirements to `associatedtype` type constraint\n    // (Ex.: `associatedtype StreamType: CollectionType where\n    // StreamType.SubSequence == Stream`)\n    \n    /// Return a parser that parses a collection of tokens.\n    ///\n    /// - parameters:\n    ///   - tokensDescription: A function to describe the tokens.\n    ///   - nextPosition: A function returning the position after the tokens.\n    ///   - tokens: The collection of tokens to parse.\n    /// - returns: A parser that parses a collection of tokens.\n    static func tokens(\n        tokensDescription: @escaping (StreamType) -> String,\n        nextPosition: @escaping (\n            SourcePosition, StreamType\n        ) -> SourcePosition,\n        tokens: StreamType\n    ) -> GenericParser<StreamType, UserState, StreamType> {\n        \n        return GenericParser(parse: { state in\n            \n            let position = state.position\n            \n            var tokensIterator = tokens.makeIterator()\n            var token = tokensIterator.next()\n            \n            guard token != nil else {\n                \n                let error = ParseError.unknownParseError(position)\n                return .none(.ok([], state, error))\n                \n            }\n            \n            var input = state.input\n            \n            var hasConsumed = false\n            var consumedConstructor =\n                Consumed<StreamType, UserState, StreamType>.none\n            \n            repeat {\n                \n                guard let inputToken = input.next() else {\n                    \n                    var eofError =\n                        ParseError.unexpectedParseError(position, message: \"\")\n                    eofError.insertMessage(.expected(tokensDescription(tokens)))\n                    \n                    return consumedConstructor(.error(eofError))\n                    \n                }\n                \n                if token! != inputToken {\n                    \n                    let tokDesc = tokensDescription([inputToken])\n                    \n                    var expectedError = ParseError.unexpectedParseError(\n                        position,\n                        message: tokDesc\n                    )\n                    \n                    let expected = Message.expected(tokensDescription(tokens))\n                    expectedError.insertMessage(expected)\n                    \n                    return consumedConstructor(.error(expectedError))\n                    \n                }\n                \n                if !hasConsumed {\n                    \n                    hasConsumed = true\n                    consumedConstructor = Consumed.some\n                    \n                }\n                \n                token = tokensIterator.next()\n                \n            } while token != nil\n            \n            let newPosition = nextPosition(position, tokens)\n            let newState = ParserState(\n                input: input,\n                position: newPosition,\n                userState: state.userState\n            )\n            let error = ParseError.unknownParseError(newPosition)\n            \n            return .some(.ok(tokens, newState, error))\n            \n        })\n        \n    }\n    \n}\n\n//==============================================================================\n/// The `Consumed` enumeration indicates if a parser consumed some or none from\n/// an input.\nenum Consumed<StreamType: Stream, UserState, Result> {\n    \n    /// Indicates that some of the input was consumed.\n    case some(ParserReply<StreamType, UserState, Result>)\n    \n    /// Indicates that none of the input was consumed.\n    case none(ParserReply<StreamType, UserState, Result>)\n    \n    /// The `ParserReply` either from `.some` or `.none`.\n    var parserReply: ParserReply<StreamType, UserState, Result> {\n        \n        switch self {\n            \n        case .some(let reply): return reply\n            \n        case .none(let reply): return reply\n            \n        }\n        \n    }\n    \n    /// Return a `Consumed` enumeration containing the result of mapping\n    /// transform over the result of the `ParserReply`. In other words it calls\n    /// `map` on the parser reply's result.\n    ///\n    /// - parameter transform: A mapping function.\n    /// - returns: A new `Consumed` enumeration with the mapped content.\n    func map<T>(\n        _ transform: (Result) -> T\n    ) -> Consumed<StreamType, UserState, T> {\n        \n        switch self {\n            \n        case .some(let reply):\n            \n            return .some(reply.map(transform))\n            \n        case .none(let reply):\n            \n            return .none(reply.map(transform))\n        }\n        \n    }\n    \n}\n\n//==============================================================================\n/// The `ParserReply` enumeration indicates the result of a parse.\nenum ParserReply<StreamType: Stream, UserState, Result> {\n    \n    /// Indicates that the parsing was successfull. It contains a `Result` type,\n    /// the `ParserState` and a `ParseError` as associated values.\n    case ok(Result, ParserState<StreamType.Iterator, UserState>, ParseError)\n    \n    /// Indicates that the parsing failed. It contains a `ParseError` as an\n    /// associated value.\n    case error(ParseError)\n    \n    /// Return a `ParserReply` enumeration containing the result of mapping\n    /// transform over `self`.\n    ///\n    /// - parameter transform: A mapping function.\n    /// - returns: A new `ParserReply` enumeration with the mapped content.\n    func map<T>(\n        _ transform: (Result) -> T\n    ) -> ParserReply<StreamType, UserState, T> {\n        \n        switch self {\n            \n        case .ok(let result, let state, let error):\n            \n            return .ok(transform(result), state, error)\n            \n        case .error(let error): return .error(error)\n            \n        }\n        \n    }\n    \n    /// Merge the `ParseError` contained by self with the supplied `ParseError`.\n    ///\n    /// - parameter otherError: The other error to merge with the error\n    ///   contained by `self`.\n    /// - returns: A new `ParserReply` with the errors merged.\n    func mergeParseError(_ otherError: ParseError) -> ParserReply {\n        \n        var mergedError = otherError\n        \n        switch self {\n            \n        case .ok(let parserResult, let parserState, let parserError):\n            \n            mergedError.merge(parserError)\n            return .ok(parserResult, parserState, mergedError)\n            \n        case .error(let parserError):\n            \n            mergedError.merge(parserError)\n            return .error(mergedError)\n            \n        }\n        \n    }\n    \n}\n\n//==============================================================================\n/// ParserState contains the state of the parser and the user state.\nstruct ParserState<StreamTypeIterator, UserState> {\n    \n    /// The input StreamType of the parser.\n    var input: StreamTypeIterator\n    \n    /// The position in the input StreamType.\n    var position: SourcePosition\n    \n    /// The supplied user state.\n    var userState: UserState\n    \n}\n\n//==============================================================================\n// Implementation of different parser operators.\n\n/// Infix operator for `map`. It has the same precedence as the equality\n/// operator (`==`).\n///\n/// - parameters:\n///   - transform: A mapping function.\n///   - parser: The parser whose result is mapped.\npublic func <^><StreamType, UserState, Result, T>(\n    transform: @escaping (Result) -> T,\n    parser: GenericParser<StreamType, UserState, Result>\n) -> GenericParser<StreamType, UserState, T> {\n    \n    return parser.map(transform)\n    \n}\n\n/// Infix operator for `apply`. It has the same precedence as the equality\n/// operator (`==`).\n///\n/// - parameters:\n///   - leftParser: The parser containing the function to apply to the parser on\n///     the right.\n///   - rightParser: The parser on which the function is applied.\n/// - returns: A parser with the applied function.\npublic func<*><StreamType, UserState, Result, T>(\n    leftParser: GenericParser<StreamType, UserState, (Result) -> T>,\n    rightParser: GenericParser<StreamType, UserState, Result>\n) -> GenericParser<StreamType, UserState, T> {\n    \n    return rightParser.apply(leftParser)\n    \n}\n\n/// Sequence parsing, discarding the value of the first parser. It has the same\n/// precedence as the equality operator (`==`).\n///\n/// - parameters:\n///   - leftParser: The first parser executed.\n///   - rightParser: The second parser executed.\n/// - returns: A parser returning the result of the second parser.\npublic func *><StreamType, UserState, Param1, Param2>(\n    leftParser: GenericParser<StreamType, UserState, Param1>,\n    rightParser: GenericParser<StreamType, UserState, Param2>\n) -> GenericParser<StreamType, UserState, Param2> {\n    \n    return GenericParser.lift2(\n        { $1 },\n        parser1: leftParser,\n        parser2: rightParser\n    )\n    \n}\n\n/// Sequence parsing, discarding the value of the second parser. It has the same\n/// precedence as the equality operator (`==`).\n///\n/// - parameters:\n///   - leftParser: The first parser executed.\n///   - rightParser: The second parser executed.\n/// - returns: A parser returning the result of the first parser.\npublic func <*<StreamType, UserState, Param1, Param2>(\n    leftParser: GenericParser<StreamType, UserState, Param1>,\n    rightParser: GenericParser<StreamType, UserState, Param2>\n) -> GenericParser<StreamType, UserState, Param1> {\n    \n    return GenericParser.lift2(\n        { p0, _ in p0 },\n        parser1: leftParser,\n        parser2: rightParser\n    )\n    \n}\n\n/// Infix operator for `flatMap` named _bind_. It has the same precedence as the\n/// `nil` coalescing operator (`??`).\n///\n/// - parameters:\n///   - parser: The parser whose result is passed to the `transform` function.\n///   - transform: The function receiving the result of `parser`.\npublic func >>-<StreamType, UserState, Result, T>(\n    parser: GenericParser<StreamType, UserState, Result>,\n    transform: @escaping (Result) -> GenericParser<StreamType, UserState, T>\n) -> GenericParser<StreamType, UserState, T> {\n    \n    return parser.flatMap(transform)\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/GenericTokenParser.swift",
    "content": "//==============================================================================\n// GenericTokenParser.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2016-10-08.\n// Copyright © 2016 David Dufresne. All rights reserved.\n//==============================================================================\n\n//==============================================================================\n/// Generic implementation of the `TokenParser`.\npublic struct GenericTokenParser<UserState>: TokenParser {\n    \n    /// Language definition parameterizing the lexer.\n    public let languageDefinition: LanguageDefinition<UserState>\n    \n    /// Creates a `TokenParser` that contains lexical parsers that are defined\n    /// using the definitions in the `LanguageDefinition` structure.\n    ///\n    /// One uses the appropiate language definition and selects the lexical\n    /// parsers that are needed from the resulting `GenericTokenParser`.\n    ///\n    ///     import SwiftParsec\n    ///\n    ///     // The lexer\n    ///     let swiftDef = LanguageDefinition<()>.swift\n    ///     let lexer = GenericTokenParser(languageDefinition: swiftDef)\n    ///\n    ///     // The parser\n    ///     let expression = lexer.identifier <|>\n    ///         lexer.legalOperator <|> ...\n    ///\n    /// - parameter languageDefinition: Language definition for the lexical\n    ///   parsers.\n    public init(languageDefinition: LanguageDefinition<UserState>) {\n        \n        self.languageDefinition = languageDefinition\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Sources/SwiftParsec/LanguageDefinition.swift",
    "content": "//==============================================================================\n// LanguageDefinition.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-14.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// A helper module that defines some language definitions that can be used to\n// instantiate a token parser (see \"Token\").\n//==============================================================================\n\n//==============================================================================\n/// The `LanguageDefinition` structure contains all parameterizable features of\n/// the token parser. There is some default definitions provided by SwiftParsec.\npublic struct LanguageDefinition<UserState> {\n    \n    /// Describe the start of a block comment. Use the empty string if the\n    /// language doesn't support block comments. For example \"/*\".\n    public var commentStart: String\n    \n    /// Describe the end of a block comment. Use the empty string if the\n    /// language doesn't support block comments. For example \"*/\".\n    public var commentEnd: String\n    \n    /// Describe the start of a line comment. Use the empty string if the\n    /// language doesn't support line comments. For example \"//\".\n    public var commentLine: String\n    \n    /// Set to `true` if the language supports nested block comments.\n    public var allowNestedComments: Bool\n    \n    /// This parser should accept any start characters of identifiers. For\n    /// example `letter <|> character(\"_\")`.\n    public var identifierStart: GenericParser<String, UserState, Character>\n    \n    /// This parser should accept any legal tail characters of identifiers. For\n    /// example `alphaNum <|> character(\"_\")`. The function receives the\n    /// character parsed by `identifierStart` as parameter, allowing to handle\n    /// special cases (i.e. implicit parameters in swift start with a '$' that\n    /// must be followed by decimal digits only).\n    public var identifierLetter:\n    (Character) -> GenericParser<String, UserState, Character>\n    \n    /// This parser should accept any start characters of operators. For example\n    /// `oneOf(\":!#$%&*+./<=>?@\\\\^|-~\")`\n    public var operatorStart: GenericParser<String, UserState, Character>\n    \n    /// This parser should accept any legal tail characters of operators. Note\n    /// that this parser should even be defined if the language doesn't support\n    /// user-defined operators, or otherwise the `reservedOperators` parser\n    /// won't work correctly.\n    public var operatorLetter: GenericParser<String, UserState, Character>\n    \n    /// The set of reserved identifiers.\n    public var reservedNames: Set<String>\n    \n    /// The set of reserved operators.\n    public var reservedOperators: Set<String>\n    \n    /// This optional parser should accept escaped characters. This parser will\n    /// also replace the string gap and zero-width escape sequence parsers. The\n    /// default escape sequences have the following form: '\\97' '\\x61', '\\o141',\n    /// '\\^@', '\\n', \\NUL.\n    public var characterEscape: GenericParser<String, UserState, Character>?\n    \n    /// Set to `true` if the language is case sensitive.\n    public var isCaseSensitive: Bool\n    \n}\n\n//==============================================================================\n// LanguageDefinition extension containing factory methods to create language\n// definitions for different languages.\npublic extension LanguageDefinition {\n    \n    /// This is the most minimal token definition. It is recommended to use this\n    /// definition as the basis for other definitions. `empty` has no reserved\n    /// names or operators, is case sensitive and doesn't accept comments,\n    /// identifiers or operators.\n    static var empty: LanguageDefinition {\n        \n        return LanguageDefinition(\n            commentStart:        \"\",\n            commentEnd:          \"\",\n            commentLine:         \"\",\n            allowNestedComments: true,\n            identifierStart:     GenericParser.letter <|>\n                GenericParser.character(\"_\"),\n            identifierLetter: { _ in\n                GenericParser.alphaNumeric <|> GenericParser.character(\"_\")\n            },\n            operatorStart:       GenericParser.oneOf(\n                emptyOperatorLetterCharacters\n            ),\n            operatorLetter:      GenericParser.oneOf(\n                emptyOperatorLetterCharacters\n            ),\n            reservedNames:       [],\n            reservedOperators:   [],\n            characterEscape:     nil,\n            isCaseSensitive:     true\n        )\n        \n    }\n    \n    /// This is a minimal token definition for Java style languages. It defines\n    /// the style of comments, valid identifiers and case sensitivity. It does\n    /// not define any reserved words or operators.\n    static var javaStyle: LanguageDefinition {\n        \n        var javaDef = empty\n        \n        javaDef.commentStart = \"/*\"\n        javaDef.commentEnd   = \"*/\"\n        javaDef.commentLine  = \"//\"\n        \n        return javaDef\n        \n    }\n    \n    // This is a definition for the JSON language-independent data interchange\n    // format.\n    static var json: LanguageDefinition {\n        \n        var jsonDef = empty\n        \n        let charEscParsers: [GenericParser<String, UserState, Character>] =\n        jsonEscapeMap.map { escCode in\n            \n            GenericParser.character(escCode.esc) *>\n                GenericParser(result: escCode.code)\n            \n        }\n        \n        let charEscape = GenericParser.choice(charEscParsers)\n        \n        let hexaNum: GenericParser<String, UserState, UInt16> =\n        GenericParser.hexadecimalDigit.count(jsonMaxEscapeDigit) >>- { digits in\n            \n            // The max possible value of `digits` is 0xFFFF, so no possible\n            // overflow.\n            let integer = UInt16(String(digits), radix: 16)!\n            return GenericParser(result: integer)\n            \n        }\n        \n        let backslash =\n            GenericParser<String, UserState, Character>.character(\"\\\\\")\n        \n        let codePoint = GenericParser.character(\"u\") *> hexaNum\n        let encodedChar: GenericParser<String, UserState, Character> =\n        codePoint >>- { cp1 in\n            \n            if cp1.isSingleCodeUnit {\n                \n                return GenericParser(result: Character(UnicodeScalar(cp1)!))\n                \n            }\n            \n            return backslash *> codePoint >>- { cp2 in\n                \n                let cps = [cp1, cp2]\n                guard let str = String(codeUnits: cps, codec: UTF16()) else {\n            \n                    let decodingErrorMsg = LocalizedString(\"decoding error\")\n                    return GenericParser.fail(decodingErrorMsg)\n                    \n                }\n                \n                return GenericParser(result: str[str.startIndex])\n                \n            } <?> LocalizedString(\"surrogate pair\")\n            \n        }\n        \n        let escapeCodeMsg = LocalizedString(\"escape code\")\n        let characterEscape = backslash *>\n            (charEscape <|> encodedChar <?> escapeCodeMsg)\n        jsonDef.characterEscape = characterEscape\n        \n        return jsonDef\n        \n    }\n    \n    /// This is a minimal token definition for the swift 2.1 language. It\n    /// defines the style of comments, valid identifiers and operators, reserved\n    /// names and operators, character escaping, and case sensitivity.\n    static var swift: LanguageDefinition {\n        \n        var swiftDef = empty\n        \n        swiftDef.commentStart = \"/*\"\n        swiftDef.commentEnd = \"*/\"\n        swiftDef.commentLine = \"//\"\n        \n        swiftDef.identifierStart =\n            GenericParser.memberOf(swiftIdentifierStartSet) <|>\n            GenericParser.character(swiftImplicitParameterStart)\n        \n        swiftDef.identifierLetter = { char in\n            \n            if char == swiftImplicitParameterStart {\n                \n                return GenericParser.decimalDigit\n                \n            }\n            \n            return GenericParser.memberOf(swiftIdentifierLetterSet)\n            \n        }\n        \n        swiftDef.operatorStart =\n            GenericParser.memberOf(swiftOperatorStartSet)\n        swiftDef.operatorLetter =\n            GenericParser.memberOf(swiftOperatorLetterSet)\n        \n        swiftDef.reservedNames = [\n            \"Self\", \"__COLUMN__\", \"__FILE__\", \"__FUNCTION__\", \"__LINE__\", \"as\",\n            \"break\", \"case\", \"catch\", \"class\", \"continue\", \"default\", \"defer\",\n            \"deinit\", \"do\", \"dynamicType\", \"else\", \"enum\", \"extension\",\n            \"fallthrough\", \"false\", \"for\", \"func\", \"guard\", \"if\", \"import\",\n            \"in\", \"init\", \"inout\", \"internal\", \"is\", \"let\", \"nil\", \"operator\",\n            \"private\", \"protocol\", \"public\", \"repeat\", \"rethrows\", \"return\",\n            \"self\", \"static­\", \"struct\", \"subscript\", \"super\", \"switch\", \"throw\",\n            \"throws\", \"true\", \"try\", \"typealias\", \"var\", \"where\", \"while\"\n        ]\n        swiftDef.reservedOperators = [\n            \"=\", \"->\", \".\", \",\", \":\", \"@\", \"#\", \"<\", \"&\", \"`\", \"?\", \">\", \"!\"\n        ]\n        \n        let charEscParsers: [GenericParser<String, UserState, Character>] =\n        swiftEscapeMap.map { escCode in\n            \n            GenericParser.character(escCode.esc) *>\n                GenericParser(result: escCode.code)\n            \n        }\n        \n        let charEscape = GenericParser.choice(charEscParsers)\n        \n        let hexaChar: GenericParser<String, UserState, Character> =\n        (GenericParser.hexadecimalDigit <?> \"\").many1 >>- { digits in\n            \n            let num = String(digits)\n            return GenericTokenParser.integerWithDigits(num, base: 16) >>-\n            { intVal in\n                \n                GenericTokenParser.characterFromInt(intVal)\n        \n            } <?> LocalizedString(\"escape sequence\")\n            \n        } <?> LocalizedString(\"hexadecimal digit(s)\")\n        \n        let charNumber =\n            GenericParser<String, UserState, Character>.string(\"u{\") *>\n            hexaChar <* GenericParser.character(\"}\")\n        \n        let escapeCodeMsg = LocalizedString(\"escape code\")\n        let characterEscape = GenericParser.character(\"\\\\\") *>\n            (charEscape <|> charNumber <?> escapeCodeMsg)\n        swiftDef.characterEscape = characterEscape\n        \n        return swiftDef\n        \n    }\n    \n}\n\n//==============================================================================\n// Private variables related to different language definitions.\n\n//\n// Empty definition\n//\nprivate let emptyOperatorLetterCharacters = \":!$%&*+./<=>?\\\\^|-~\"\n\n//\n// JSON definition\n//\nprivate let jsonEscapeMap: [(esc: Character, code: Character)] = [\n    (\"\\\"\", \"\\\"\"), (\"\\\\\", \"\\\\\"), (\"/\", \"/\"), (\"b\", \"\\u{0008}\"),\n    (\"f\", \"\\u{000C}\"), (\"n\", \"\\n\"), (\"r\", \"\\r\"), (\"t\", \"\\t\")\n]\n\nprivate let jsonMaxEscapeDigit = 4\n\n//\n// Swift definition\n//\nprivate let swiftImplicitParameterStart: Character = \"$\"\n\n// Initialized this way to overcome Swift 4.2 compiler error\nprivate let swiftIdentifierStartCharacters: String = {\n    let strands: [String] = [\n        (0x0041...0x005A).stringValue, // 'A' to 'Z'\n        (0x0061...0x007A).stringValue, // 'a' to 'z'\n        \"_\",\n        \"\\u{00A8}\\u{00AA}\\u{00AD}\\u{00AF}\",\n        (0x00B2...0x00B5).stringValue,\n        (0x00B7...0x00BA).stringValue,\n        (0x00BC...0x00BE).stringValue,\n        (0x00C0...0x00D6).stringValue,\n        (0x00D8...0x00F6).stringValue,\n        (0x00F8...0x00FF).stringValue,\n        (0x0100...0x02FF).stringValue,\n        (0x0370...0x167F).stringValue,\n        (0x1681...0x180D).stringValue,\n        (0x180F...0x1DBF).stringValue,\n        (0x1E00...0x1FFF).stringValue,\n        (0x200B...0x200D).stringValue,\n        (0x202A...0x202E).stringValue,\n        (0x203F...0x2040).stringValue,\n        \"\\u{2054}\",\n        (0x2060...0x206F).stringValue,\n        (0x2070...0x20CF).stringValue,\n        (0x2100...0x218F).stringValue,\n        (0x2460...0x24FF).stringValue,\n        (0x2776...0x2793).stringValue,\n        (0x2C00...0x2DFF).stringValue,\n        (0x2E80...0x2FFF).stringValue,\n        (0x3004...0x3007).stringValue,\n        (0x3021...0x302F).stringValue,\n        (0x3031...0x303F).stringValue,\n        (0x3040...0xD7FF).stringValue,\n        (0xF900...0xFD3D).stringValue,\n        (0xFD40...0xFDCF).stringValue,\n        (0xFDF0...0xFE1F).stringValue,\n        (0xFE30...0xFE44).stringValue,\n        (0xFE47...0xFFFD).stringValue,\n        (0x10000...0x1FFFD).stringValue,\n        (0x20000...0x2FFFD).stringValue,\n        (0x30000...0x3FFFD).stringValue,\n        (0x40000...0x4FFFD).stringValue,\n        (0x50000...0x5FFFD).stringValue,\n        (0x60000...0x6FFFD).stringValue,\n        (0x70000...0x7FFFD).stringValue,\n        (0x80000...0x8FFFD).stringValue,\n        (0x90000...0x9FFFD).stringValue,\n        (0xA0000...0xAFFFD).stringValue,\n        (0xB0000...0xBFFFD).stringValue,\n        (0xC0000...0xCFFFD).stringValue,\n        (0xD0000...0xDFFFD).stringValue,\n        (0xE0000...0xEFFFD).stringValue]\n    return strands.reduce(into: \"\") { $0 += $1 }\n}()\n\nprivate let swiftIdentifierStartSet =\n    CharacterSet(charactersIn: swiftIdentifierStartCharacters)\n\nprivate let swiftIdentifierLetterCharacters =\n    swiftIdentifierStartCharacters +\n    \"0123456789\" +\n    (0x0300...0x036F).stringValue +\n    (0x1DC0...0x1DFF).stringValue +\n    (0x20D0...0x20FF).stringValue +\n    (0xFE20...0xFE2F).stringValue\n\nprivate let swiftIdentifierLetterSet =\n    CharacterSet(charactersIn: swiftIdentifierLetterCharacters)\n\nprivate let swiftOperatorStartCharacters =\n    \"/=-+!*%<>&|^?~\" +\n    (0x00A1...0x00A7).stringValue +\n    \"\\u{00A9}\\u{00AB}\" +\n    \"\\u{00AC}\\u{00AE}\" +\n    \"\\u{00B0}\\u{00B1}\\u{00B6}\\u{00BB}\\u{00BF}\\u{00D7}\\u{00F7}\" +\n    (0x2016...0x2017).stringValue +\n    (0x2020...0x2027).stringValue +\n    (0x2030...0x203E).stringValue +\n    (0x2041...0x2053).stringValue +\n    (0x2055...0x205E).stringValue +\n    (0x2190...0x23FF).stringValue +\n    (0x2500...0x2775).stringValue +\n    (0x2794...0x2BFF).stringValue +\n    (0x2E00...0x2E7F).stringValue +\n    (0x3001...0x3003).stringValue +\n    (0x3008...0x3030).stringValue\n\nprivate let swiftOperatorStartSet =\n    CharacterSet(charactersIn: swiftOperatorStartCharacters)\n\nprivate let swiftOperatorLetterCharacters =\n    swiftOperatorStartCharacters +\n    (0x0300...0x036F).stringValue +\n    (0x1DC0...0x1DFF).stringValue +\n    (0x20D0...0x20FF).stringValue +\n    (0xFE00...0xFE0F).stringValue +\n    (0xFE20...0xFE2F).stringValue +\n    (0xE0100...0xE01EF).stringValue\n\nprivate let swiftOperatorLetterSet =\n    CharacterSet(charactersIn: swiftOperatorLetterCharacters)\n\nprivate let swiftEscapeMap: [(esc: Character, code: Character)] = [\n    (\"n\", \"\\n\"), (\"r\", \"\\r\"), (\"t\", \"\\t\"), (\"\\\\\", \"\\\\\"), (\"\\\"\", \"\\\"\"),\n    (\"'\", \"'\"), (\"0\", \"\\0\")\n]\n"
  },
  {
    "path": "Sources/SwiftParsec/ParseError.swift",
    "content": "//==============================================================================\n// Error.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-04.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// Parse errors.\n//==============================================================================\n\n//==============================================================================\n/// Message represents parse error messages. The fine distinction between\n/// different kinds of parse errors allows the system to generate quite good\n/// error messages for the user. It also allows error messages that are\n/// formatted in different languages. Each kind of message is generated by\n/// different combinators.\n///\n/// The `Comparable` protocol is implemented based on the index of a message.\npublic enum Message: Comparable {\n    \n    /// A `SystemUnexpected` message is automatically generated by the\n    /// `satisfy` combinator. The argument is the unexpected input.\n    case systemUnexpected(String)\n    \n    /// An `Unexpected` message is generated by the `unexpected` combinator.\n    /// The argument describes the unexpected item.\n    case unexpected(String)\n    \n    /// An `Expect` message is generated by the `<?>` combinator. The argument\n    /// describes the expected item.\n    case expected(String)\n    \n    /// A `Generic` message is generated by the `fail` combinator. The argument\n    /// is some general parser message.\n    case generic(String)\n    \n    /// The index of the message type.\n    var index: Int {\n        \n        switch self {\n            \n        case .systemUnexpected: return 0\n            \n        case .unexpected: return 1\n            \n        case .expected: return 2\n            \n        case .generic: return 3\n            \n        }\n        \n    }\n    \n    /// The message string.\n    var messageString: String {\n        \n        switch self {\n            \n        case .systemUnexpected(let str): return str\n            \n        case .unexpected(let str): return str\n        \n        case .expected(let str): return str\n        \n        case .generic(let str): return str\n            \n        }\n        \n    }\n    \n}\n\n//==============================================================================\n// Operator implementations for the `Message` type.\n\n/// Equality based on the index.\npublic func ==(leftMsg: Message, rightMsg: Message) -> Bool {\n    \n    return leftMsg.index == rightMsg.index\n    \n}\n\n/// Comparison based on the index.\npublic func <(leftMsg: Message, rightMsg: Message) -> Bool {\n    \n    return leftMsg.index < rightMsg.index\n    \n}\n\n//==============================================================================\n/// `ParseError` represents parse errors. It provides the source position\n/// (`SourcePosition`) of the error and an array of error messages (`Message`).\n/// A `ParseError` can be returned by the function `parse`.\npublic struct ParseError: Error, CustomStringConvertible {\n    \n    /// Return an unknown parse error.\n    ///\n    /// - parameter position: The current position.\n    /// - returns: An unknown parse error.\n    static func unknownParseError(_ position: SourcePosition) -> ParseError {\n        \n        return ParseError(position: position, messages: [])\n        \n    }\n    \n    /// Return a system unexpected parse error.\n    ///\n    /// - parameters:\n    ///   - position: The current position.\n    ///   - message: The message string.\n    /// - returns: An unexpected parse error.\n    static func unexpectedParseError(\n        _ position: SourcePosition,\n        message: String\n    ) -> ParseError {\n        \n        return ParseError(\n            position: position,\n            messages: [.systemUnexpected(message)]\n        )\n        \n    }\n    \n    /// Source position of the error.\n    public var position: SourcePosition\n    \n    /// Sorted array of error messages.\n    public var messages: [Message] {\n        \n        get { return _messages.sorted() }\n        \n        set { _messages = newValue }\n        \n    }\n    \n    // Backing store for `messages`.\n    private var _messages = [Message]()\n    \n    /// A textual representation of `self`.\n    public var description: String {\n        \n        return String(describing: position) + \":\\n\" + messagesDescription\n        \n    }\n    \n    /// Indicates if `self` is an unknown parse error.\n    var isUnknown: Bool { return messages.isEmpty }\n    \n    private var messagesDescription: String {\n        \n        guard !messages.isEmpty else {\n            \n            return LocalizedString(\"unknown parse error\")\n            \n        }\n        \n        let (sysUnexpected, msgs1) =\n            messages.part { $0 == .systemUnexpected(\"\") }\n        let (unexpected, msgs2) = msgs1.part { $0 == .unexpected(\"\") }\n        let (expected, generic) = msgs2.part { $0 == .expected(\"\") }\n        \n        // System unexpected messages.\n        let sysUnexpectedDesc: String\n        \n        let unexpectedMsg = LocalizedString(\"unexpected\")\n        \n        if !unexpected.isEmpty || sysUnexpected.isEmpty {\n            \n            sysUnexpectedDesc = \"\"\n            \n        } else {\n            \n            let firstMsg = sysUnexpected.first!.messageString\n            \n            if firstMsg.isEmpty {\n                \n                sysUnexpectedDesc = LocalizedString(\"unexpected end of input\")\n                \n            } else {\n                \n                sysUnexpectedDesc = unexpectedMsg + \" \" + firstMsg\n                \n            }\n            \n        }\n        \n        // Unexpected messages.\n        let unexpectedDesc =\n            formatMessages(unexpected, havingType: unexpectedMsg)\n        \n        // Expected messages.\n        let expectingMsg = LocalizedString(\"expecting\")\n        let expectedDesc = formatMessages(expected, havingType: expectingMsg)\n        \n        // Generic messages.\n        let genericDesc = formatMessages(generic, havingType: \"\")\n        \n        let descriptions = [\n            sysUnexpectedDesc, unexpectedDesc, expectedDesc, genericDesc\n        ]\n        \n        return descriptions.removingDuplicatesAndEmpties().joined(\n            separator: \"\\n\"\n        )\n        \n    }\n    \n    /// Initializes from a source position and an array of messages.\n    init(position: SourcePosition, messages: [Message]) {\n        \n        self.position = position\n        self.messages = messages\n        \n    }\n    \n    /// Insert a message error in `messages`. All messages equal to the inserted\n    /// messages are removed and the new message is inserted at the beginning of\n    /// `messages`.\n    ///\n    /// - parameter message: The new message to insert in `messages`.\n    mutating func insertMessage(_ message: Message) {\n        \n        messages = messages.filter({ $0 != message }).prepending(message)\n        \n    }\n    \n    /// Insert the labels as `.Expected` message errors in `messages`.\n    ///\n    /// - parameter labels: The labels to insert.\n    mutating func insertLabelsAsExpected(_ labels: [String]) {\n        \n        guard !labels.isEmpty else {\n            \n            insertMessage(.expected(\"\"))\n            return\n            \n        }\n        \n        insertMessage(.expected(labels[0]))\n        \n        for label in labels.suffix(from: 1) {\n            \n            messages.append(.expected(label))\n            \n        }\n        \n    }\n    \n    /// Merge this `ParseError` with another `ParseError`.\n    ///\n    /// - parameter other: `ParseError` to merge with `self`.\n    mutating func merge(_ other: ParseError) {\n        \n        let otherIsEmpty = other.messages.isEmpty\n        \n        // Prefer meaningful error.\n        if messages.isEmpty && !otherIsEmpty {\n            \n            self = other\n            \n        } else if !otherIsEmpty {\n            \n            // Select the longest match\n            if position == other.position {\n                \n                messages += other.messages\n                \n            } else if position < other.position {\n                \n                self = other\n                \n            }\n            \n        }\n        \n    }\n    \n    private func formatMessages(\n        _ messages: [Message],\n        havingType messageType: String\n    ) -> String {\n        \n        let msgs = messages.map({\n            $0.messageString\n        }).removingDuplicatesAndEmpties()\n        \n        guard !msgs.isEmpty else { return \"\" }\n        \n        let msgType = messageType.isEmpty ? \"\" : messageType + \" \"\n        \n        if msgs.count == 1 {\n            \n            return msgType + msgs.first!\n            \n        }\n        \n        let commaSep = msgs.dropLast().joined(separator: \", \")\n        \n        let orStr =  LocalizedString(\"or\")\n        \n        return msgType + commaSep + \" \" + orStr + \" \" + msgs.last!\n        \n    }\n\n}\n\n//==============================================================================\n// Extension to add ad-hoc methods on the `Sequence` type.\nextension Sequence where Iterator.Element == String {\n    \n    /// Return an array with duplicate and empty strings removed.\n    func removingDuplicatesAndEmpties() -> [Self.Iterator.Element] {\n        \n        return self.removingDuplicates().filter { !$0.isEmpty }\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/Parsec.swift",
    "content": "//==============================================================================\n// Parsec.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2016-05-02.\n// Copyright © 2016 David Dufresne. All rights reserved.\n//\n// Parsec protocol and related operator definitions.\n//==============================================================================\n\n// TODO: - Make `Parsec` the model of a true monad when Swift will allow it.\n\n//==============================================================================\n/// `Parsec` is a parser with stream type `Stream`, user state type `UserState`\n/// and return type `Result`.\npublic protocol Parsec {\n    \n    /// The input stream to parse.\n    associatedtype StreamType: Stream\n    \n    /// The state supplied by the user.\n    associatedtype UserState\n    \n    /// The result of the parser.\n    associatedtype Result\n    \n    /// Return a parser containing the result of mapping transform over `self`.\n    ///\n    /// This method has the synonym infix operator `<^>`.\n    ///\n    /// - parameter transform: A mapping function.\n    /// - returns: A new parser with the mapped content.\n    func map<T>(\n        _ transform: @escaping (Result) -> T\n    ) -> GenericParser<StreamType, UserState, T>\n    \n    /// Return a parser by applying the function contained in the supplied\n    /// parser to self.\n    ///\n    /// This method has the synonym infix operator `<*>`.\n    ///\n    /// - parameter parser: The parser containing the function to apply to self.\n    /// - returns: A parser with the applied function.\n    func apply<T>(\n        _ parser: GenericParser<StreamType, UserState, (Result) -> T>\n    ) -> GenericParser<StreamType, UserState, T>\n    \n    /// This combinator implements choice. The parser `p.alternative(q)` first\n    /// applies `p`. If it succeeds, the value of `p` is returned. If `p` fails\n    /// _without consuming any input_, parser `q` is tried. The parser is called\n    /// _predictive_ since `q` is only tried when parser `p` didn't consume any\n    /// input (i.e.. the look ahead is 1). This non-backtracking behaviour\n    /// allows for both an efficient implementation of the parser combinators\n    /// and the generation of good error messages.\n    ///\n    /// This method has the synonym infix operator `<|>`.\n    ///\n    /// - parameter altParser: The alternative parser to try if `self` fails.\n    /// - returns: A parser that will first try `self`. If it consumed no input,\n    ///   it will try `altParser`.\n    func alternative(_ altParser: Self) -> Self\n    \n    /// Return a parser containing the result of mapping transform over `self`.\n    ///\n    /// This method has the synonym infix operator `>>-` (bind).\n    ///\n    /// - parameter transform: A mapping function returning a parser.\n    /// - returns: A new parser with the mapped content.\n    func flatMap<T>(\n        _ transform: @escaping (\n            Result\n        ) -> GenericParser<StreamType, UserState, T>\n    ) -> GenericParser<StreamType, UserState, T>\n    \n    /// This combinator is used whenever arbitrary look ahead is needed. Since\n    /// it pretends that it hasn't consumed any input when `self` fails, the\n    /// ('<|>') combinator will try its second alternative even when the first\n    /// parser failed while consuming input.\n    ///\n    /// The `attempt` combinator can for example be used to distinguish\n    /// identifiers and reserved words. Both reserved words and identifiers are\n    /// a sequence of letters. Whenever we expect a certain reserved word where\n    /// we can also expect an identifier we have to use the `attempt`\n    /// combinator. Suppose we write:\n    ///\n    ///     let letExpr = StringParser.string(\"let\")\n    ///     let identifier = letter.many1\n    ///\n    ///     let expr = letExpr <|> identifier <?> \"expression\"\n    ///\n    /// If the user writes \\\"lexical\\\", the parser fails with: _unexpected 'x',\n    /// expecting 't' in \"let\"_. Indeed, since the ('<|>') combinator only tries\n    /// alternatives when the first alternative hasn't consumed input, the\n    /// `identifier` parser is never tried (because the prefix \"le\" of the\n    /// `string(\"let\")` parser is already consumed). The right behaviour can be\n    /// obtained by adding the `attempt` combinator:\n    ///\n    ///     let letExpr = StringParser.string(\"let\")\n    ///     let identifier = StringParser.letter.many1\n    ///\n    ///     let expr = letExpr.attempt <|> identifier <?> \"expression\"\n    ///\n    /// - returns: A parser that pretends that it hasn't consumed any input when\n    ///   `self` fails.\n    var attempt: Self { get }\n    \n    /// A combinator that parses without consuming any input.\n    ///\n    /// If `self` fails and consumes some input, so does `lookAhead`. Combine\n    /// with `attempt` if this is undesirable.\n    ///\n    /// - returns: A parser that parses without consuming any input.\n    var lookAhead: Self { get }\n    \n    /// This combinator applies `self` _zero_ or more times. It returns an\n    /// accumulation of the returned values of `self` that were passed to the\n    /// `accumulator` function.\n    ///\n    /// - parameter accumulator: An accumulator function that process the value\n    ///   returned by `self`. The first argument is the value returned by `self`\n    ///   and the second argument is the previous processed values returned by\n    ///   this accumulator function. It returns the result of processing the\n    ///   passed value and the accumulated values.\n    /// - returns: The processed values of the accumulator function.\n    func manyAccumulator(\n        _ accumulator: @escaping (Result, [Result]) -> [Result]\n    ) -> GenericParser<StreamType, UserState, [Result]>\n    \n    /// A parser that always fails without consuming any input.\n    static var empty: Self { get }\n    \n    /// The parser returned by `p.labels(message)` behaves as parser `p`, but\n    /// whenever the parser `p` fails _without consuming any input_, it replaces\n    /// expected error messages with the expected error message `message`.\n    ///\n    /// This is normally used at the end of a set alternatives where we want to\n    /// return an error message in terms of a higher level construct rather than\n    /// returning all possible characters. For example, if the `expr` parser\n    /// from the `attempt` example would fail, the error message is: '...:\n    /// expecting expression'. Without the `GenericParser.labels()` combinator,\n    /// the message would be like '...: expecting \"let\" or \"letter\"', which is\n    /// less friendly.\n    ///\n    /// This method has the synonym infix operator `<?>`.\n    ///\n    /// - parameter message: The new error message.\n    /// - returns: A parser with a replaced error message.\n    func labels(_ message: String...) -> Self\n    \n    /// Return a parser that always fails with an unexpected error message\n    /// without consuming any input.\n    ///\n    /// The parsers 'fail', '\\<?\\>' and `unexpected` are the three parsers used\n    /// to generate error messages. Of these, only '<?>' is commonly used. For\n    /// an example of the use of `unexpected`, see the definition of\n    /// `GenericParser.noOccurence`.\n    ///\n    /// - parameter message: The error message.\n    /// - returns: A parser that always fails with an unexpected error message\n    ///   without consuming any input.\n    /// - SeeAlso: `GenericParser.noOccurence`, `GenericParser.fail(message:\n    ///   String)` and `<?>`\n    static func unexpected(_ message: String) -> Self\n    \n    /// Return a parser that always fails with the supplied message.\n    ///\n    /// - parameter message: The failure message.\n    /// - returns: A parser that always fail.\n    static func fail(_ message: String) -> Self\n    \n    /// Return the current source position.\n    ///\n    /// - returns: The current source position.\n    /// - SeeAlso 'SourcePosition'.\n    static var\n    sourcePosition: GenericParser<StreamType, UserState, SourcePosition> { get }\n    \n    /// Return the user state.\n    ///\n    /// - returns: The user state\n    static var\n    userState: GenericParser<StreamType, UserState, UserState> { get }\n    \n    /// The `updateUserState` method applies the function `update` to the user\n    /// state. Suppose that we want to count identifiers in a source, we could\n    /// use the user state as:\n    ///\n    ///     let incrementCount = StringParser.updateUserState { ++$0 }\n    ///     let expr = identifier <* incrementCount\n    ///\n    /// - parameter update: The function applied to the `UserState`. It returns\n    ///   the updated `UserState`.\n    /// - returns: An empty parser that will update the `UserState`.\n    static func updateUserState(\n        _ update: @escaping (UserState) -> UserState\n    ) -> GenericParser<StreamType, UserState, ()>\n    \n    /// Run the parser and return the result of the parsing if it succeeded.\n    /// If an error occured, it is returned. Contrary to the `run()` method, it\n    /// doesn't throw an exception.\n    ///\n    /// - parameters:\n    ///   - userState: The state supplied by the user.\n    ///   - sourceName: The name of the source (i.e. file name).\n    ///   - input: The input StreamType to parse.\n    /// - returns: The result of the parsing on success, otherwise the parse\n    ///   error.\n    func runSafe(\n        userState: UserState,\n        sourceName: String,\n        input: StreamType\n    ) -> Either<ParseError, Result>\n    \n}\n\n//==============================================================================\n// Operator definitions.\n\n/// Precedence of infix operator for `Parsec.labels()`. It has a higher\n/// precedence than the `AssignmentPrecedence` group but a lower precedence than\n/// the `LogicalDisjunctionPrecedence` group.\nprecedencegroup LabelPrecedence {\n    associativity: right\n    higherThan: AssignmentPrecedence\n    lowerThan: LogicalDisjunctionPrecedence\n}\n\n/// Infix operator for `Parsec.labels()`. It has the lowest precedence of the\n/// parsers operators.\ninfix operator <?> : LabelPrecedence\n\n/// Precedence of infix operator for `Parsec.flatMap()` (bind). It has a higher\n/// precedence than the `LabelPrecedence` group.\nprecedencegroup FlatMapPrecedence {\n    associativity: left\n    higherThan: LabelPrecedence\n}\n\n/// Infix operator for `Parsec.flatMap()` (bind). It has a higher precedence\n/// than the `<?>` operator.\ninfix operator >>- : FlatMapPrecedence\n\n/// Precedence of infix operator for `Parsec.alternative()`. It has a higher\n/// precedence than the `FlatMapPrecedence` group.\nprecedencegroup ChoicePrecedence {\n    associativity: left\n    higherThan: FlatMapPrecedence\n}\n\n/// Infix operator for `Parsec.alternative()`. It has a higher precedence than\n/// the `>>-` operator.\ninfix operator <|> : ChoicePrecedence\n\n/// Precedence of infix operators for sequence parsing. It has a higher\n/// precedence than the `ChoicePrecedence` group.\nprecedencegroup SequencePrecedence {\n    associativity: left\n    higherThan: ChoicePrecedence\n}\n\n/// Sequence parsing, discarding the value of the first parser. It has a higher\n/// precedence than the `<|>` operator.\ninfix operator *> : SequencePrecedence\n\n/// Sequence parsing, discarding the value of the second parser. It has a higher\n/// precedence than the `<|>` operator.\ninfix operator <* : SequencePrecedence\n\n/// Infix operator for `Parsec.apply()`. It has a higher precedence than the\n/// `<|>` operator.\ninfix operator <*> : SequencePrecedence\n\n/// Infix operator for `Parsec.map()`. It has a higher precedence than the `<|>`\n/// operator.\ninfix operator <^> : SequencePrecedence\n\nextension Parsec {\n    \n    /// Infix operator for `Parsec.labels()`. It has the lowest precedence of the\n    /// parsers operators.\n    ///\n    /// - parameters:\n    ///   - parser: The parser whose error message is to be replaced.\n    ///   - message: The new error message.\n    public static func <?>(parser: Self, message: String) -> Self {\n        \n        return parser.labels(message)\n        \n    }\n    \n    /// Infix operator for `Parsec.alternative`. It has a higher precedence than\n    /// the `>>-` operator.\n    ///\n    /// - parameters:\n    ///   - leftParser: The first parser to try.\n    ///   - rightParser: The second parser to try.\n    public static func <|>(leftParser: Self, rightParser: Self) -> Self {\n        \n        return leftParser.alternative(rightParser)\n        \n    }\n   \n}\n\n//==============================================================================\n// Extension containing useful methods to run a parser.\npublic extension Parsec {\n    \n    /// Run the parser and return the result of the parsing.\n    ///\n    /// - parameters:\n    ///   - userState: The state supplied by the user.\n    ///   - sourceName: The name of the source (i.e. file name).\n    ///   - input: The input stream to parse.\n    /// - throws: A `ParseError` when an error occurs.\n    /// - returns: The result of the parsing.\n    func run(\n        userState: UserState,\n        sourceName: String,\n        input: StreamType\n        ) throws -> Result {\n        \n        let result = runSafe(\n            userState: userState,\n            sourceName: sourceName,\n            input: input\n        )\n        \n        switch result {\n            \n        case .left(let error):\n            \n            throw error\n            \n        case .right(let result):\n            \n            return result\n            \n        }\n        \n    }\n    \n}\n\n//==============================================================================\n// Extension containing useful methods to run a parser with an empty user state.\npublic extension Parsec where UserState == () {\n    \n    /// Run the parser and return the result of the parsing.\n    ///\n    /// - parameters:\n    ///   - userState: The state supplied by the user.\n    ///   - sourceName: The name of the source (i.e. file name).\n    ///   - input: The input stream to parse.\n    /// - throws: A `ParseError` when an error occurs.\n    /// - returns: The result of the parsing.\n    func run(sourceName: String, input: StreamType) throws -> Result {\n        \n        return try run(\n            userState: (),\n            sourceName: sourceName,\n            input: input\n        )\n        \n    }\n    \n    /// Used for testing parsers. It applies `self` against `input` and prints\n    /// the result.\n    ///\n    /// - parameter input: The input stream to parse.\n    func test(input: StreamType) {\n        \n        do {\n            \n            let result = try run(sourceName: \"\", input: input)\n            print(result)\n            \n        } catch let parseError as ParseError {\n            \n            let parseErrorMsg = LocalizedString(\"parse error at \")\n            print(parseErrorMsg + String(describing: parseError))\n            \n        } catch let error {\n            \n            print(String(describing: error))\n            \n        }\n        \n    }\n    \n}\n\n//==============================================================================\n// Extension containing useful methods to run a parser.\n/// A `Stream` instance is responsible for maintaining the position of the\n/// parser's stream.\npublic protocol Stream: Collection, ExpressibleByArrayLiteral\nwhere ArrayLiteralElement == Element {}\n\nextension String: Stream {\n    \n    /// Create an instance containing `elements`.\n    public init(arrayLiteral elements: String.Iterator.Element...) {\n        \n        self.init(elements)\n        \n    }\n    \n}\n\n//==============================================================================\n/// Types conforming to the `EmptyInitializable` protocol provide an empty\n/// intializer.\npublic protocol EmptyInitializable {\n    \n    init()\n    \n}\n\n\n//==============================================================================\n// Extensions implementing the `Stream` protocol for various collections.\n\nextension Array: Stream, EmptyInitializable {}\n\nextension ContiguousArray: Stream, EmptyInitializable {}\n\nextension ArraySlice: Stream, EmptyInitializable {}\n\nextension Dictionary: EmptyInitializable {}\n\nextension Set: EmptyInitializable {}\n"
  },
  {
    "path": "Sources/SwiftParsec/Permutation.swift",
    "content": "//==============================================================================\n// Permutation.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-11-01.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// This module implements permutation parsers.\n//==============================================================================\n\n//==============================================================================\n/// The type `Permutation` denotes a permutation that can be converted to a\n/// `GenericParser` that returns an array of values of type `Result` on success.\n/// The values in the array have the same order as the parsers in the\n/// permutation. In the following exemple `parser` applies to any permutation of\n/// the characters 'a', 'b' and 'c' and always returns the string `\"abc\"` on\n/// success.\n///\n///     let permutation: Permutation = [\n///\n///         (StringParser.character(\"a\"), nil),\n///         (StringParser.character(\"b\"), nil),\n///         (StringParser.character(\"c\"), nil)\n///\n///     ]\n///\n///     let parser = permutation.parser.stringValue\n///\npublic struct Permutation<StreamType: Stream, UserState, Result>:\nRangeReplaceableCollection, ExpressibleByArrayLiteral {\n    \n    /// Represents a valid position in the permutation.\n    public typealias Index = Int\n    \n    /// Permutation's generator.\n    public typealias Iterator = IndexingIterator<Permutation>\n    \n    /// Element type of the permutation.\n    public typealias Element = (\n        parser: GenericParser<StreamType, UserState, Result>,\n        otherwise: Result?\n    )\n    \n    /// The position of the first element.\n    public let startIndex = 0\n    \n    /// The permutation's \"past the end\" position.\n    public var endIndex: Int { return parsers.count }\n    \n    // Backing store.\n    private var parsers: [Element]\n    \n    /// Create an instance initialized with elements.\n    ///\n    /// - parameter arrayLiteral: Arrays of tuple containing a parser and an\n    ///   optional default value.\n    public init(arrayLiteral elements: Element...) {\n        \n        parsers = elements\n        \n    }\n    \n    /// Create an empty instance.\n    public init() { parsers = [] }\n    \n    /// Returns the position immediately after i.\n    ///\n    /// - SeeAlso: `IndexableBase` protocol.\n    public func index(after i: Permutation.Index) -> Permutation.Index {\n        \n        return parsers.index(after: i)\n        \n    }\n    \n    /// A parser applying to the permutation of all the parsers contained in\n    /// `self`.\n    public func makeParser() -> GenericParser<StreamType, UserState, [Result]> {\n        \n        return makeParser(separator: GenericParser(result: ()))\n        \n    }\n    \n    /// A parser applying to the permutation of all the parsers contained in\n    /// `self` separated by `separator`.\n    ///\n    /// - parameter separator: A separator to apply between each element of the\n    ///   permutation.\n    public func makeParser<Separator>(\n        separator: GenericParser<StreamType, UserState, Separator>\n    ) -> GenericParser<StreamType, UserState, [Result]> {\n        \n        let ps = parsers.map { elem in\n            \n            (parser: elem.parser.map { [$0] }, otherwise: elem.otherwise)\n            \n        }\n        \n        return permute(ps, separator: separator)\n        \n    }\n    \n    private typealias PermParser =\n        GenericParser<StreamType, UserState, [Result]>\n    \n    private func permute<Separator>(\n        _ elements: [(parser: PermParser, otherwise: Result?)],\n        separator: GenericParser<StreamType, UserState, Separator>\n    ) -> PermParser {\n        \n        var permutation = ContiguousArray<PermParser>()\n        \n        let elementsRange = elements.indices\n        for index in elementsRange {\n            \n            let element = elements[index]\n            \n            var parser = element.parser\n            if index == elementsRange.last {\n                \n                parser = emptyParser(parser, otherwise: element.otherwise)\n                \n            }\n            \n            let perm: PermParser = parser >>- { result in\n                \n                var elems = elements\n                elems.remove(at: index)\n                \n                let p: PermParser\n                if elems.count > 1  {\n                    \n                    p = separator *> self.permute(elems, separator: separator)\n                    \n                } else {\n                    \n                    let elem = elems[0]\n                    p = self.emptyParser(\n                        separator *> elem.parser,\n                        otherwise: elem.otherwise\n                    )\n                    \n                }\n                \n                return p >>- { results in\n                    \n                    var rs = results\n                    rs.insert(contentsOf: result, at: index)\n                    \n                    return GenericParser(result: rs)\n                    \n                }\n                \n            }\n            \n            permutation.append(perm)\n            \n        }\n        \n        return GenericParser.choice(permutation)\n        \n    }\n    \n    private func emptyParser(\n        _ parser: PermParser,\n        otherwise: Result?\n    ) -> PermParser {\n        \n        guard let def = otherwise else { return parser }\n        \n        return parser.otherwise([def])\n        \n    }\n    \n    /// Append a parser to the permutation. The added parser is not allowed to\n    /// accept empty input - use `appendOptionalParser` instead.\n    ///\n    /// - parameter parser: The parser to append to the permutation.\n    public mutating func appendParser(\n        _ parser: GenericParser<StreamType, UserState, Result>\n    ) {\n        \n        parsers.append((parser, nil))\n        \n    }\n    \n    /// Append an optional parser to the permutation. The parser is optional -\n    /// if it cannot be applied, the default value `otherwise` will be used\n    /// instead.\n    ///\n    /// - parameters:\n    ///   - parser: The optional parser to append to the permutation.\n    ///   - otherwise: The default value to use if the parser cannot be applied.\n    public mutating func appendOptionalParser(\n        _ parser: GenericParser<StreamType, UserState, Result>,\n        otherwise: Result\n    ) {\n        \n        parsers.append((parser, otherwise))\n        \n    }\n    \n    /// Replace the given subRange of elements with newElements.\n    ///\n    /// - parameters:\n    ///   - subRange: Range of elements to replace.\n    ///   - newElements: New elements replacing the previous elements contained\n    ///     in `subRange`.\n    public mutating func replaceSubrange<C: Collection>(\n        _ subrange: Range<Index>,\n        with newElements: C\n    ) where C.Iterator.Element == Iterator.Element {\n        \n        parsers.replaceSubrange(subrange, with: newElements)\n        \n    }\n    \n    public subscript(position: Index) -> Element { return parsers[position] }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/Position.swift",
    "content": "//==============================================================================\n// Position.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-04.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// Textual source positions.\n//==============================================================================\n\n//==============================================================================\n/// SourcePosition represents source positions. It contains the name of the\n/// source (i.e. file name), a line number and a column number. The upper left\n/// is 1, 1. It implements the `Comparable` and `CustomStringConvertible`\n/// protocols. The comparison is made using line and column number.\npublic struct SourcePosition: Comparable, CustomStringConvertible {\n    \n    /// The name of the source (i.e. file name)\n    public var name: String\n    \n    /// The line number in the source.\n    public var line: Int\n    \n    /// The column number in the source.\n    public var column: Int\n    \n    /// A textual representation of `self`.\n    public var description: String {\n        \n        let lineMsg = LocalizedString(\"line\")\n        let columnMsg = LocalizedString(\"column\")\n        \n        var desc = \"(\" + lineMsg + \" \\(line), \" + columnMsg + \" \\(column))\"\n        \n        if !name.isEmpty {\n            \n            desc = \"\\\"\\(name)\\\" \" + desc\n            \n        }\n        \n        return desc\n        \n    }\n    \n    /// Update a source position given a character. If the character is a\n    /// newline (\"\\n\") or carriage return (\"\\r\") the line number is incremented\n    /// by 1. If the character is a tab (\"\\t\") the column number is incremented\n    /// to the nearest 8'th column, ie. `column + 8 - ((column - 1) % 8)`. In\n    /// all other cases, the column is incremented by 1.\n    ///\n    /// - parameter char: The tested character indicating how to update the\n    ///   position.\n    mutating func updatePosition(_ char: Character) {\n        \n        switch char {\n            \n        case \"\\n\":\n            \n            line += 1\n            column = 1\n            \n        case \"\\t\":\n            \n            column = column + 8 - ((column - 1) % 8)\n            \n        default: column += 1\n            \n        }\n        \n    }\n    \n}\n\n//==============================================================================\n// Operator implementations for the `SourcePosition` type.\n\n/// Equality based on the line and column number.\npublic func ==(leftPos: SourcePosition, rightPos: SourcePosition) -> Bool {\n    \n    return leftPos.line == rightPos.line && leftPos.column == rightPos.column\n    \n}\n\n/// Comparison based on the line and column number.\npublic func <(leftPos: SourcePosition, rightPos: SourcePosition) -> Bool {\n    \n    if leftPos.line < rightPos.line {\n        \n        return true\n        \n    } else if leftPos.line == rightPos.line {\n        \n        if leftPos.column < rightPos.column { return true }\n        \n    }\n    \n    return false\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/RangeReplaceableCollectionInsertion.swift",
    "content": "//==============================================================================\n// RangeReplaceableCollectionInsertion.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-11.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// RangeReplaceableCollection extension\n//==============================================================================\n\n//==============================================================================\n// Extension containing insertion methods.\npublic extension RangeReplaceableCollection {\n    \n    /// Prepend `newElement` to the collection.\n    ///\n    /// - parameter newElement: New element to prepend to the collection.\n    mutating func prepend(_ newElement: Iterator.Element) {\n        \n        insert(newElement, at: startIndex)\n        \n    }\n    \n    /// Returns a new collection containing the elements of `self` with\n    /// `newElement` prepended at the beginning.\n    ///\n    /// - parameter newElement: New element to prepend.\n    /// - returns: A copy of `self` plus `newElement` prepended.\n    func prepending(_ newElement: Iterator.Element) -> Self {\n        \n        var mutableSelf = self\n        mutableSelf.prepend(newElement)\n        \n        return mutableSelf\n        \n    }\n    \n    /// Returns a new collection containing the elements of `self` with\n    /// `newElement` appended to the end.\n    ///\n    /// - parameter newElement: New element to append.\n    /// - returns: A copy of `self` plus `newElement` appended.\n    func appending(_ newElement: Iterator.Element) -> Self {\n        \n        var mutableSelf = self\n        mutableSelf.append(newElement)\n        \n        return mutableSelf\n        \n    }\n\n}\n"
  },
  {
    "path": "Sources/SwiftParsec/SequenceAggregation.swift",
    "content": "//==============================================================================\n// SequenceAggregation.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-14.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// Sequence extension\n//==============================================================================\n\n//==============================================================================\n// Extension containing aggregation methods.\nextension Sequence {\n    \n    /// Return a tuple containing the elements of `self`, in order, that satisfy\n    /// the predicate `includeElement`. The second array of the tuple contains\n    /// the remainder of the list.\n    ///\n    /// - parameter includeElement: The predicate function used to split the\n    ///   sequence.\n    /// - returns:\n    ///   - included: The elements that satisfied the predicate.\n    ///   - remainder: The remainder of `self`.\n    func part(\n        _ includeElement: (Self.Iterator.Element) throws -> Bool\n    ) rethrows\n    -> (included: [Self.Iterator.Element], remainder: [Self.Iterator.Element]) {\n        \n        var included: [Self.Iterator.Element] = []\n        var remainder: [Self.Iterator.Element] = []\n        \n        for elem in self {\n            \n            if (try includeElement(elem)) {\n                \n                included.append(elem)\n                \n            } else {\n                \n                remainder.append(elem)\n                \n            }\n            \n        }\n        \n        return (included, remainder)\n        \n    }\n    \n}\n\n//==============================================================================\n// Extension containing aggregation methods when the `Sequence` contains\n// elements that are `Equatable`.\nextension Sequence where Iterator.Element: Equatable {\n    \n    /// Return an array with the duplicate elements removed. In particular, it\n    /// keeps only the first occurrence of each element.\n    ///\n    /// - returns: An array with the duplicate elements removed.\n    func removingDuplicates() -> [Self.Iterator.Element] {\n        \n        return reduce([]) { (acc, elem) in\n            \n            guard !acc.contains(elem) else { return acc }\n            \n            return acc.appending(elem)\n            \n        }\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/SequenceConversion.swift",
    "content": "//==============================================================================\n// SequenceConversion.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2016-09-24.\n// Copyright © 2016 David Dufresne. All rights reserved.\n//\n// Sequence extension\n//==============================================================================\n\n//==============================================================================\n// Extension containing conversion methods.\nextension Sequence where Iterator.Element == Int {\n    \n    /// Converts each `Int` in its `Character` equivalent and build a String\n    /// with the result.\n    var stringValue: String {\n        \n        let chars = map { Character(UnicodeScalar($0)!) }\n        \n        return String(chars)\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/SetAggregation.swift",
    "content": "//==============================================================================\n// SetAggregation.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-10.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// Set extension\n//==============================================================================\n\n//==============================================================================\n// Extension containing aggregation methods.\nextension Set {\n    \n    /// Return a `Set` containing the results of mapping transform over `self`.\n    ///\n    /// - parameter transform: The transform function.\n    /// - returns: A `Set` containing the results of mapping transform over\n    ///   `self`.\n    func map<T>(\n        _ transform: (Iterator.Element) throws -> T\n    ) rethrows -> Set<T> {\n        \n        var mappedSet = Set<T>()\n        \n        for elem in self {\n            \n            mappedSet.insert(try transform(elem))\n            \n        }\n        \n        return mappedSet\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/String.swift",
    "content": "//==============================================================================\n// String.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-10.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// String extension\n//==============================================================================\n\n//==============================================================================\n// Extension containing various utility methods and initializers.\nextension String {\n    \n    /// Initialize a `String` from a sequence of code units.\n    ///\n    /// - parameters:\n    ///   - codeUnits: Sequence of code units.\n    ///   - codec: A unicode encoding scheme.\n    init?<C: UnicodeCodec, S: Sequence>(codeUnits: S, codec: C)\n    where S.Iterator.Element == C.CodeUnit {\n        \n        var unicodeCode = codec\n        var str = \"\"\n        \n        var iterator = codeUnits.makeIterator()\n        var done = false\n        while !done {\n            \n            let result = unicodeCode.decode(&iterator)\n            switch result {\n                \n            case .emptyInput: done = true\n                \n            case let .scalarValue(val):\n                \n                str.append(Character(val))\n                \n            case .error: return nil\n                \n            }\n            \n        }\n        \n        self = str\n        \n    }\n    \n    /// The last character of the string.\n    ///\n    /// If the string is empty, the value of this property is `nil`.\n    var last: Character? {\n        \n        guard !isEmpty else { return nil }\n        \n        return self[index(before: endIndex)]\n        \n    }\n    \n    /// Return a new `String` with `c` adjoined to the end.\n    ///\n    /// - parameter c: Character to append.\n    func appending(_ c: Character) -> String {\n        \n        var mutableSelf = self\n        mutableSelf.append(c)\n        \n        return mutableSelf\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/TokenParser.swift",
    "content": "//==============================================================================\n// TokenParser.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-05.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// A helper module to parse lexical elements (tokens). See the initializer for\n// the `TokenParser` structure for a description of how to use it.\n// Operator implementations for the `Message` type.\n//==============================================================================\n\nimport func Foundation.pow\n\n//==============================================================================\n/// Types implementing this protocol hold lexical parsers.\npublic protocol TokenParser {\n    \n    /// The state supplied by the user.\n    associatedtype UserState\n    \n    /// Language definition parameterizing the lexer.\n    var languageDefinition: LanguageDefinition<UserState> { get }\n    \n    /// This lexeme parser parses a legal identifier. Returns the identifier\n    /// string. This parser will fail on identifiers that are reserved words.\n    /// Legal identifier (start) characters and reserved words are defined in\n    /// the `LanguageDefinition` that is passed to the initializer of this token\n    /// parser. An `identifier` is treated as a single token using\n    /// `GenericParser.attempt`.\n    var identifier: GenericParser<String, UserState, String> { get }\n    \n    /// The lexeme parser `reservedName(name)` parses `symbol(name)`, but it\n    /// also checks that the `name` is not a prefix of a valid identifier. A\n    /// _reserved_ word is treated as a single token using\n    /// `GenericParser.attempt`.\n    ///\n    /// - parameter name: The reserved name to parse.\n    /// - returns: A parser returning nothing.\n    func reservedName(_ name: String) -> GenericParser<String, UserState, ()>\n    \n    /// This lexeme parser parses a legal operator and returns the name of the\n    /// operator. This parser will fail on any operators that are reserved\n    /// operators. Legal operator (start) characters and reserved operators are\n    /// defined in the `LanguageDefinition` that is passed to the initializer of\n    /// this token parser. An 'operator' is treated as a single token using\n    /// `GenericParser.attempt`.\n    var legalOperator: GenericParser<String, UserState, String> { get }\n    \n    /// The lexeme parser `reservedOperator(name)` parses `symbol(name)`, but it\n    /// also checks that the `name` is not a prefix of a valid operator. A\n    /// 'reservedOperator' is treated as a single token using\n    /// `GenericParser.attempt`.\n    ///\n    /// - parameter name: The operator name.\n    /// - returns: A parser returning nothing.\n    func reservedOperator(\n        _ name: String\n    ) -> GenericParser<String, UserState, ()>\n    \n    /// This lexeme parser parses a single literal character and returns the\n    /// literal character value. This parser deals correctly with escape\n    /// sequences.\n    var characterLiteral: GenericParser<String, UserState, Character> { get }\n    \n    /// This lexeme parser parses a literal string and returns the literal\n    /// string value. This parser deals correctly with escape sequences and\n    /// gaps.\n    var stringLiteral: GenericParser<String, UserState, String> { get }\n    \n    /// This lexeme parser parses a natural number (a positive whole number) and\n    /// returns the value of the number. The number can be specified in\n    /// 'decimal', 'hexadecimal' or 'octal'.\n    var natural: GenericParser<String, UserState, Int> { get }\n    \n    /// This lexeme parser parses an integer (a whole number). This parser is\n    /// like `natural` except that it can be prefixed with sign (i.e. \"-\" or\n    /// \"+\"). It returns the value of the number. The number can be specified in\n    /// 'decimal', 'hexadecimal' or 'octal'.\n    var integer: GenericParser<String, UserState, Int> { get }\n    \n    /// This lexeme parser parses an integer (a whole number). It is like\n    /// `integer` except that it can parse bigger numbers. Returns the value of\n    /// the number as a `Double`.\n    var integerAsFloat: GenericParser<String, UserState, Double> { get }\n    \n    /// This lexeme parser parses a floating point value and returns the value\n    /// of the number.\n    var float: GenericParser<String, UserState, Double> { get }\n    \n    /// This lexeme parser parses either `integer` or a `float` and returns the\n    /// value of the number. This parser deals with any overlap in the grammar\n    /// rules for integers and floats.\n    var number: GenericParser<String, UserState, Either<Int, Double>> { get }\n    \n    /// Parses a positive whole number in the decimal system. Returns the value\n    /// of the number.\n    static var decimal: GenericParser<String, UserState, Int> { get }\n    \n    /// Parses a positive whole number in the hexadecimal system. The number\n    /// should be prefixed with \"x\" or \"X\". Returns the value of the number.\n    static var hexadecimal: GenericParser<String, UserState, Int> { get }\n    \n    /// Parses a positive whole number in the octal system. The number should be\n    /// prefixed with \"o\" or \"O\". Returns the value of the number.\n    static var octal: GenericParser<String, UserState, Int> { get }\n    \n    /// Lexeme parser `symbol(str)` parses `str` and skips trailing white space.\n    ///\n    /// - parameter name: The name of the symbol to parse.\n    /// - returns: `name`.\n    func symbol(_ name: String) -> GenericParser<String, UserState, String>\n    \n    /// `lexeme(parser)` first applies `parser` and than the `whiteSpace`\n    /// parser, returning the value of `parser`. Every lexical token (lexeme) is\n    /// defined using `lexeme`, this way every parse starts at a point without\n    /// white space. Parsers that use `lexeme` are called _lexeme_ parsers in\n    /// this document.\n    ///\n    /// The only point where the 'whiteSpace' parser should be called explicitly\n    /// is the start of the main parser in order to skip any leading white\n    /// space.\n    ///\n    ///     let mainParser = sum <^> whiteSpace *> lexeme(digit) <* eof\n    ///\n    /// - parameter parser: The parser to transform in a 'lexeme'.\n    /// - returns: The value of `parser`.\n    func lexeme<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result>\n    \n    /// Parses any white space. White space consists of _zero_ or more\n    /// occurrences of a 'space', a line comment or a block (multiline) comment.\n    /// Block comments may be nested. How comments are started and ended is\n    /// defined in the `LanguageDefinition` that is passed to the initializer of\n    /// this token parser.\n    var whiteSpace: GenericParser<String, UserState, ()> { get }\n    \n    /// Lexeme parser `parentheses(parser)` parses `parser` enclosed in\n    /// parentheses, returning the value of `parser`.\n    ///\n    /// - parameter parser: The parser applied between the parentheses.\n    /// - returns: The value of `parser`.\n    func parentheses<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result>\n    \n    /// Lexeme parser `braces(parser)` parses `parser` enclosed in braces \"{\"\n    /// and \"}\", returning the value of `parser`.\n    ///\n    /// - parameter parser: The parser applied between the braces.\n    /// - returns: The value of `parser`.\n    func braces<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result>\n    \n    /// Lexeme parser `angles(parser)` parses `parser` enclosed in angle\n    /// brackets \"<\" and \">\", returning the value of `parser`.\n    ///\n    /// - parameter parser: The parser applied between the angles.\n    /// - returns: The value of `parser`.\n    func angles<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result>\n    \n    /// Lexeme parser `brackets(parser)` parses `parser` enclosed in brackets\n    /// \"[\" and \"]\", returning the value of `parser`.\n    ///\n    /// - parameter parser: The parser applied between the brackets.\n    /// - returns: The value of `parser`.\n    func brackets<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result>\n    \n    /// Lexeme parser `semicolon` parses the character \";\" and skips any\n    /// trailing white space. Returns the string \";\".\n    var semicolon: GenericParser<String, UserState, String> { get }\n    \n    /// Lexeme parser `comma` parses the character \",\" and skips any trailing\n    /// white space. Returns the string \",\".\n    var comma: GenericParser<String, UserState, String> { get }\n    \n    /// Lexeme parser `colon` parses the character \":\" and skips any trailing\n    /// white space. Returns the string \":\".\n    var colon: GenericParser<String, UserState, String> { get }\n    \n    /// Lexeme parser `dot` parses the character \".\" and skips any trailing\n    /// white space. Returns the string \".\".\n    var dot: GenericParser<String, UserState, String> { get }\n    \n    /// Lexeme parser `semicolonSeperated(parser)` parses _zero_ or more\n    /// occurrences of `parser` separated by `semicolon`. Returns an array of\n    /// values returned by `parser`.\n    ///\n    /// - parameter parser: The parser applied between semicolons.\n    /// - returns: An array of values returned by `parser`.\n    func semicolonSeparated<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, [Result]>\n    \n    /// Lexeme parser `semicolonSeperated1(parser)` parses _one_ or more\n    /// occurrences of `parser` separated by `semicolon`. Returns an array of\n    /// values returned by `parser`.\n    ///\n    /// - parameter parser: The parser applied between semicolons.\n    /// - returns: An array of values returned by `parser`.\n    func semicolonSeparated1<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, [Result]>\n    \n    /// Lexeme parser `commaSeparated(parser)` parses _zero_ or more occurrences\n    /// of `parser` separated by `comma`. Returns an array of values returned by\n    /// `parser`.\n    ///\n    /// - parameter parser: The parser applied between commas.\n    /// - returns: An array of values returned by `parser`.\n    func commaSeparated<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, [Result]>\n    \n    /// Lexeme parser `commaSeparated1(parser)` parses _one_ or more occurrences\n    /// of `parser` separated by `comma`. Returns an array of values returned by\n    /// `parser`.\n    ///\n    /// - parameter parser: The parser applied between commas.\n    /// - returns: An array of values returned by `parser`.\n    func commaSeparated1<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, [Result]>\n    \n}\n\n// Default implementation of the methods of the `TokenParser` parser type.\nextension TokenParser {\n    \n    // Type aliases used internally to simplify the code.\n    typealias StrParser = GenericParser<String, UserState, String>\n    typealias CharacterParser = GenericParser<String, UserState, Character>\n    typealias IntParser = GenericParser<String, UserState, Int>\n    typealias DoubleParser = GenericParser<String, UserState, Double>\n    typealias IntDoubleParser =\n        GenericParser<String, UserState, Either<Int, Double>>\n    typealias VoidParser = GenericParser<String, UserState, ()>\n    \n    //\n    // Identifiers & Reserved words\n    //\n    \n    /// This lexeme parser parses a legal identifier. Returns the identifier\n    /// string. This parser will fail on identifiers that are reserved words.\n    /// Legal identifier (start) characters and reserved words are defined in\n    /// the `LanguageDefinition` that is passed to the initializer of this token\n    /// parser. An `identifier` is treated as a single token using\n    /// `GenericParser.attempt`.\n    public var identifier: GenericParser<String, UserState, String> {\n        \n        let langDef = languageDefinition\n        \n        let ident: StrParser = langDef.identifierStart >>- { char in\n            \n            langDef.identifierLetter(char).many >>- { chars in\n                \n                let cs = chars.prepending(char)\n                return GenericParser(result: String(cs))\n                \n            }\n            \n        } <?> LocalizedString(\"identifier\")\n        \n        let identCheck: StrParser = ident >>- { name in\n            \n            let reservedNames: Set<String>\n            let n: String\n            \n            if langDef.isCaseSensitive {\n                \n                reservedNames = langDef.reservedNames\n                n = name\n                \n            } else {\n                \n                reservedNames = langDef.reservedNames.map { $0.lowercased() }\n                n = name.lowercased()\n                \n            }\n            \n            guard !reservedNames.contains(n) else {\n                \n                let reservedWordMsg = LocalizedString(\"reserved word \")\n                return GenericParser.unexpected(reservedWordMsg + name)\n                \n            }\n            \n            return GenericParser(result: name)\n            \n        }\n        \n        return lexeme(identCheck.attempt)\n        \n    }\n    \n    /// The lexeme parser `reservedName(name)` parses `symbol(name)`, but it\n    /// also checks that the `name` is not a prefix of a valid identifier. A\n    /// _reserved_ word is treated as a single token using\n    /// `GenericParser.attempt`.\n    ///\n    /// - parameter name: The reserved name to parse.\n    /// - returns: A parser returning nothing.\n    public func reservedName(\n        _ name: String\n    ) -> GenericParser<String, UserState, ()> {\n        \n        let lastChar = name.last!\n        let reserved = caseString(name) *>\n            languageDefinition.identifierLetter(lastChar).noOccurence <?>\n            LocalizedString(\"end of \") + name\n        \n        return lexeme(reserved.attempt)\n        \n    }\n    \n    //\n    // Operators & reserved operators\n    //\n    \n    /// This lexeme parser parses a legal operator and returns the name of the\n    /// operator. This parser will fail on any operators that are reserved\n    /// operators. Legal operator (start) characters and reserved operators are\n    /// defined in the `LanguageDefinition` that is passed to the initializer of\n    /// this token parser. An 'operator' is treated as a single token using\n    /// `GenericParser.attempt`.\n    public var legalOperator: GenericParser<String, UserState, String> {\n        \n        let langDef = languageDefinition\n        \n        let op: StrParser = langDef.operatorStart >>- { char in\n            \n            langDef.operatorLetter.many >>- { chars in\n                \n                let cs = chars.prepending(char)\n                return GenericParser(result: String(cs))\n                \n            }\n            \n        } <?> LocalizedString(\"operator\")\n        \n        let opCheck: StrParser = op >>- { name in\n            \n            guard !langDef.reservedOperators.contains(name) else {\n                \n                let reservedOperatorMsg = LocalizedString(\"reserved operator \")\n                return GenericParser.unexpected(reservedOperatorMsg + name)\n                \n            }\n            \n            return GenericParser(result: name)\n            \n        }\n        \n        return lexeme(opCheck.attempt)\n        \n    }\n    \n    /// The lexeme parser `reservedOperator(name)` parses `symbol(name)`, but it\n    /// also checks that the `name` is not a prefix of a valid operator. A\n    /// 'reservedOperator' is treated as a single token using\n    /// `GenericParser.attempt`.\n    ///\n    /// - parameter name: The operator name.\n    /// - returns: A parser returning nothing.\n    public func reservedOperator(\n        _ name: String\n    ) -> GenericParser<String, UserState, ()> {\n        \n        let op = VoidParser.string(name) *>\n            languageDefinition.operatorLetter.noOccurence <?>\n            LocalizedString(\"end of \") + name\n        \n        return lexeme(op.attempt)\n        \n    }\n    \n    //\n    // Characters & Strings\n    //\n    \n    /// This lexeme parser parses a single literal character and returns the\n    /// literal character value. This parser deals correctly with escape\n    /// sequences.\n    public var characterLiteral: GenericParser<String, UserState, Character> {\n        \n        let characterLetter = CharacterParser.satisfy { char in\n            \n            char != \"'\" && char != \"\\\\\" && char != substituteCharacter\n            \n        }\n        \n        let defaultCharEscape = GenericParser.character(\"\\\\\") *>\n            GenericTokenParser<UserState>.escapeCode\n        let characterEscape =\n            languageDefinition.characterEscape ?? defaultCharEscape\n        \n        let character = characterLetter <|> characterEscape <?>\n            LocalizedString(\"literal character\")\n        \n        let quote = CharacterParser.character(\"'\")\n        \n        let endOfCharMsg = LocalizedString(\"end of character\")\n        \n        return lexeme(character.between(quote, quote <?> endOfCharMsg)) <?>\n            LocalizedString(\"character\")\n        \n    }\n    \n    /// This lexeme parser parses a literal string and returns the literal\n    /// string value. This parser deals correctly with escape sequences and\n    /// gaps.\n    public var stringLiteral: GenericParser<String, UserState, String> {\n        \n        let stringLetter = CharacterParser.satisfy { char in\n            \n            char != \"\\\"\" && char != \"\\\\\" && char != substituteCharacter\n            \n        }\n        \n        let escapeGap: GenericParser<String, UserState, Character?> =\n            GenericParser.space.many1 *> GenericParser.character(\"\\\\\") *>\n                GenericParser(result: nil) <?>\n                LocalizedString(\"end of string gap\")\n        \n        let escapeEmpty: GenericParser<String, UserState, Character?> =\n            GenericParser.character(\"&\") *> GenericParser(result: nil)\n        \n        let characterEscape: GenericParser<String, UserState, Character?> =\n            GenericParser.character(\"\\\\\") *>\n                (escapeGap <|> escapeEmpty <|>\n                GenericTokenParser.escapeCode.map { $0 })\n        \n        let stringEscape =\n            languageDefinition.characterEscape?.map { $0 } ?? characterEscape\n        \n        let stringChar = stringLetter.map { $0 } <|> stringEscape\n        \n        let doubleQuote = CharacterParser.character(\"\\\"\")\n        let endOfStringMsg = LocalizedString(\"end of string\")\n        let string = stringChar.many.between(\n            doubleQuote, doubleQuote <?> endOfStringMsg\n        )\n        \n        let literalString = string.map({ str in\n            \n            str.reduce(\"\") { (acc, char) in\n                \n                guard let c = char else { return acc }\n                \n                return acc.appending(c)\n                \n            }\n            \n        }) <?> LocalizedString(\"literal string\")\n        \n        return lexeme(literalString)\n        \n    }\n    \n    //\n    // Numbers\n    //\n    \n    /// This lexeme parser parses a natural number (a positive whole number) and\n    /// returns the value of the number. The number can be specified in\n    /// 'decimal', 'hexadecimal' or 'octal'.\n    public var natural: GenericParser<String, UserState, Int> {\n        \n        return lexeme(GenericTokenParser.naturalNumber) <?>\n            LocalizedString(\"natural\")\n        \n    }\n    \n    /// This lexeme parser parses an integer (a whole number). This parser is\n    /// like `natural` except that it can be prefixed with sign (i.e. \"-\" or\n    /// \"+\"). It returns the value of the number. The number can be specified in\n    /// 'decimal', 'hexadecimal' or 'octal'.\n    public var integer: GenericParser<String, UserState, Int> {\n        \n        let int = lexeme(GenericTokenParser.sign()) >>- { f in\n            \n            GenericTokenParser.naturalNumber >>- {\n                \n                GenericParser(result: f($0))\n                \n            }\n            \n        }\n        \n        return lexeme(int) <?> LocalizedString(\"integer\")\n        \n    }\n    \n    /// This lexeme parser parses an integer (a whole number). It is like\n    /// `integer` except that it can parse bigger numbers. Returns the value of\n    /// the number as a `Double`.\n    public var integerAsFloat: GenericParser<String, UserState, Double> {\n        \n        let hexaPrefix = CharacterParser.oneOf(hexadecimalPrefixes)\n        let hexa = hexaPrefix *> GenericTokenParser.doubleWithBase(\n            16,\n            parser: GenericParser.hexadecimalDigit\n        )\n        \n        let octPrefix = CharacterParser.oneOf(octalPrefixes)\n        let oct = octPrefix *> GenericTokenParser.doubleWithBase(\n            8,\n            parser: GenericParser.octalDigit\n        )\n        \n        let decDigit = CharacterParser.decimalDigit\n        let dec = GenericTokenParser.doubleWithBase(10, parser: decDigit)\n        \n        let zeroNumber = (GenericParser.character(\"0\") *>\n            (hexa <|> oct <|> dec <|> GenericParser(result: 0))) <?> \"\"\n        \n        let nat = zeroNumber <|> dec\n        \n        let double = lexeme(GenericTokenParser.sign()) >>- { sign in\n            \n            nat >>- { GenericParser(result: sign($0)) }\n            \n        }\n        \n        return lexeme(double) <?> LocalizedString(\"integer\")\n        \n    }\n    \n    /// This lexeme parser parses a floating point value and returns the value\n    /// of the number.\n    public var float: GenericParser<String, UserState, Double> {\n        \n        let intPart = GenericTokenParser<UserState>.doubleIntegerPart\n        let expPart = GenericTokenParser<UserState>.fractionalExponent\n        let f = intPart >>- { expPart($0) }\n        \n        let double = lexeme(GenericTokenParser.sign()) >>- { sign in\n            \n            f >>- { GenericParser(result: sign($0)) }\n            \n        }\n        \n        return lexeme(double) <?> LocalizedString(\"float\")\n        \n    }\n    \n    /// This lexeme parser parses either `integer` or a `float` and returns the\n    /// value of the number. This parser deals with any overlap in the grammar\n    /// rules for integers and floats.\n    public var number: GenericParser<String, UserState, Either<Int, Double>> {\n        \n        let intDouble = float.map({ Either.right($0) }).attempt <|>\n            integer.map({ Either.left($0) })\n        \n        return lexeme(intDouble) <?> LocalizedString(\"number\")\n    }\n    \n    /// Parses a positive whole number in the decimal system. Returns the value\n    /// of the number.\n    public static var decimal: GenericParser<String, UserState, Int> {\n        \n        return numberWithBase(10, parser: GenericParser.decimalDigit)\n        \n    }\n    \n    /// Parses a positive whole number in the hexadecimal system. The number\n    /// should be prefixed with \"x\" or \"X\". Returns the value of the number.\n    public static var hexadecimal: GenericParser<String, UserState, Int> {\n        \n        return GenericParser.oneOf(hexadecimalPrefixes) *>\n            numberWithBase(16, parser: GenericParser.hexadecimalDigit)\n        \n    }\n    \n    /// Parses a positive whole number in the octal system. The number should be\n    /// prefixed with \"o\" or \"O\". Returns the value of the number.\n    public static var octal: GenericParser<String, UserState, Int> {\n        \n        return GenericParser.oneOf(octalPrefixes) *>\n            numberWithBase(8, parser: GenericParser.octalDigit)\n        \n    }\n    \n    //\n    // White space & symbols\n    //\n    \n    /// Lexeme parser `symbol(str)` parses `str` and skips trailing white space.\n    ///\n    /// - parameter name: The name of the symbol to parse.\n    /// - returns: `name`.\n    public func symbol(\n        _ name: String\n    ) -> GenericParser<String, UserState, String> {\n        \n        return lexeme(StrParser.string(name))\n        \n    }\n    \n    /// `lexeme(parser)` first applies `parser` and than the `whiteSpace`\n    /// parser, returning the value of `parser`. Every lexical token (lexeme) is\n    /// defined using `lexeme`, this way every parse starts at a point without\n    /// white space. Parsers that use `lexeme` are called _lexeme_ parsers in\n    /// this document.\n    ///\n    /// The only point where the 'whiteSpace' parser should be called explicitly\n    /// is the start of the main parser in order to skip any leading white\n    /// space.\n    ///\n    ///     let mainParser = sum <^> whiteSpace *> lexeme(digit) <* eof\n    ///\n    /// - parameter parser: The parser to transform in a 'lexeme'.\n    /// - returns: The value of `parser`.\n    public func lexeme<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result> {\n        \n        return parser <* whiteSpace\n        \n    }\n    \n    /// Parses any white space. White space consists of _zero_ or more\n    /// occurrences of a 'space', a line comment or a block (multiline) comment.\n    /// Block comments may be nested. How comments are started and ended is\n    /// defined in the `LanguageDefinition` that is passed to the initializer of\n    /// this token parser.\n    public var whiteSpace: GenericParser<String, UserState, ()> {\n        \n        let simpleSpace = CharacterParser.satisfy({ $0.isSpace }).skipMany1\n        \n        let commentLineEmpty = languageDefinition.commentLine.isEmpty\n        let commentStartEmpty = languageDefinition.commentStart.isEmpty\n        \n        if commentLineEmpty && commentStartEmpty {\n            \n            return (simpleSpace <?> \"\").skipMany\n            \n        }\n        \n        if commentLineEmpty {\n            \n            return (simpleSpace <|> multiLineComment <?> \"\").skipMany\n            \n        }\n        \n        if commentStartEmpty {\n            \n            return (simpleSpace <|> oneLineComment <?> \"\").skipMany\n            \n        }\n        \n        return (\n            simpleSpace <|> oneLineComment <|> multiLineComment <?> \"\"\n        ).skipMany\n        \n    }\n    \n    //\n    // Bracketing\n    //\n    \n    /// Lexeme parser `parentheses(parser)` parses `parser` enclosed in\n    /// parentheses, returning the value of `parser`.\n    ///\n    /// - parameter parser: The parser applied between the parentheses.\n    /// - returns: The value of `parser`.\n    public func parentheses<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result> {\n        \n        return parser.between(symbol(\"(\"), symbol(\")\"))\n        \n    }\n    \n    /// Lexeme parser `braces(parser)` parses `parser` enclosed in braces \"{\"\n    /// and \"}\", returning the value of `parser`.\n    ///\n    /// - parameter parser: The parser applied between the braces.\n    /// - returns: The value of `parser`.\n    public func braces<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result> {\n        \n        return parser.between(symbol(\"{\"), symbol(\"}\"))\n        \n    }\n    \n    /// Lexeme parser `angles(parser)` parses `parser` enclosed in angle\n    /// brackets \"<\" and \">\", returning the value of `parser`.\n    ///\n    /// - parameter parser: The parser applied between the angles.\n    /// - returns: The value of `parser`.\n    public func angles<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result> {\n        \n        return parser.between(symbol(\"<\"), symbol(\">\"))\n        \n    }\n    \n    /// Lexeme parser `brackets(parser)` parses `parser` enclosed in brackets\n    /// \"[\" and \"]\", returning the value of `parser`.\n    ///\n    /// - parameter parser: The parser applied between the brackets.\n    /// - returns: The value of `parser`.\n    public func brackets<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, Result> {\n        \n        return parser.between(symbol(\"[\"), symbol(\"]\"))\n        \n    }\n    \n    /// Lexeme parser `semicolon` parses the character \";\" and skips any\n    /// trailing white space. Returns the string \";\".\n    public var semicolon: GenericParser<String, UserState, String> {\n        \n        return symbol(\";\")\n        \n    }\n    \n    /// Lexeme parser `comma` parses the character \",\" and skips any trailing\n    /// white space. Returns the string \",\".\n    public var comma: GenericParser<String, UserState, String> {\n        \n        return symbol(\",\")\n        \n    }\n    \n    /// Lexeme parser `colon` parses the character \":\" and skips any trailing\n    /// white space. Returns the string \":\".\n    public var colon: GenericParser<String, UserState, String> {\n        \n        return symbol(\":\")\n        \n    }\n    \n    /// Lexeme parser `dot` parses the character \".\" and skips any trailing\n    /// white space. Returns the string \".\".\n    public var dot: GenericParser<String, UserState, String> {\n        \n        return symbol(\".\")\n        \n    }\n    \n    /// Lexeme parser `semicolonSeperated(parser)` parses _zero_ or more\n    /// occurrences of `parser` separated by `semicolon`. Returns an array of\n    /// values returned by `parser`.\n    ///\n    /// - parameter parser: The parser applied between semicolons.\n    /// - returns: An array of values returned by `parser`.\n    public func semicolonSeparated<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, [Result]> {\n        \n        return parser.separatedBy(semicolon)\n        \n    }\n    \n    /// Lexeme parser `semicolonSeperated1(parser)` parses _one_ or more\n    /// occurrences of `parser` separated by `semicolon`. Returns an array of\n    /// values returned by `parser`.\n    ///\n    /// - parameter parser: The parser applied between semicolons.\n    /// - returns: An array of values returned by `parser`.\n    public func semicolonSeparated1<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, [Result]> {\n        \n        return parser.separatedBy1(semicolon)\n        \n    }\n    \n    /// Lexeme parser `commaSeparated(parser)` parses _zero_ or more occurrences\n    /// of `parser` separated by `comma`. Returns an array of values returned by\n    /// `parser`.\n    ///\n    /// - parameter parser: The parser applied between commas.\n    /// - returns: An array of values returned by `parser`.\n    public func commaSeparated<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, [Result]> {\n        \n        return parser.separatedBy(comma)\n        \n    }\n    \n    /// Lexeme parser `commaSeparated1(parser)` parses _one_ or more occurrences\n    /// of `parser` separated by `comma`. Returns an array of values returned by\n    /// `parser`.\n    ///\n    /// - parameter parser: The parser applied between commas.\n    /// - returns: An array of values returned by `parser`.\n    public func commaSeparated1<Result>(\n        _ parser: GenericParser<String, UserState, Result>\n    ) -> GenericParser<String, UserState, [Result]> {\n        \n        return parser.separatedBy1(comma)\n        \n    }\n    \n    //\n    // Private methods. They sould be in a separate private extension but it\n    // causes problems with the internal typealiases.\n    //\n    \n    private var oneLineComment: VoidParser {\n        \n        let commentStart = StrParser.string(languageDefinition.commentLine)\n        \n        return commentStart.attempt *>\n            GenericParser.satisfy({ $0 != \"\\n\"}).skipMany *>\n            GenericParser(result: ())\n        \n    }\n    \n    private var multiLineComment: VoidParser {\n        \n        return GenericParser {\n            \n            let commentStart =\n                StrParser.string(self.languageDefinition.commentStart)\n            \n            return commentStart.attempt *> self.inComment\n            \n        }\n        \n    }\n    \n    private var inComment: VoidParser {\n        \n        return languageDefinition.allowNestedComments ?\n            inNestedComment : inNonNestedComment\n        \n    }\n    \n    private var inNestedComment: VoidParser {\n        \n        return GenericParser {\n            \n            let langDef = self.languageDefinition\n            \n            let startEnd = (\n                langDef.commentStart + langDef.commentEnd\n                ).removingDuplicates()\n            let commentEnd = StrParser.string(langDef.commentEnd)\n            \n            return commentEnd.attempt *> GenericParser(result: ()) <|>\n                self.multiLineComment *> self.inNestedComment <|>\n                GenericParser.noneOf(String(startEnd)).skipMany1 *>\n                self.inNestedComment <|>\n                GenericParser.oneOf(String(startEnd)) *>\n                self.inNestedComment <?>\n                LocalizedString(\"end of comment\")\n            \n        }\n        \n    }\n    \n    private var inNonNestedComment: VoidParser {\n        \n        return GenericParser {\n            \n            let langDef = self.languageDefinition\n            \n            let startEnd = (\n                langDef.commentStart + langDef.commentEnd\n            ).removingDuplicates()\n            let commentEnd = StrParser.string(langDef.commentEnd)\n            \n            return commentEnd.attempt *> GenericParser(result: ()) <|>\n                GenericParser.noneOf(String(startEnd)).skipMany1 *>\n                self.inNonNestedComment <|>\n                GenericParser.oneOf(String(startEnd)) *>\n                self.inNonNestedComment <?>\n                LocalizedString(\"end of comment\")\n            \n        }\n        \n    }\n    \n    private static var escapeCode: CharacterParser {\n        \n        return charEscape <|> charNumber <|> charAscii <|> charControl <?>\n            LocalizedString(\"escape code\")\n        \n    }\n    \n    private static var charEscape: CharacterParser {\n        \n        let parsers = escapeMap.map { escCode in\n            \n            CharacterParser.character(escCode.esc) *>\n                GenericParser(result: escCode.code)\n            \n        }\n        \n        return GenericParser.choice(parsers)\n        \n    }\n    \n    private static var charNumber: CharacterParser {\n        \n        let octalDigit = CharacterParser.octalDigit\n        let hexaDigit = CharacterParser.hexadecimalDigit\n        \n        let num = decimal <|>\n            GenericParser.character(\"o\") *>\n            numberWithBase(8, parser: octalDigit) <|>\n            GenericParser.character(\"x\") *>\n            numberWithBase(16, parser: hexaDigit)\n        \n        return num >>- { characterFromInt($0) }\n        \n    }\n    \n    private static var charAscii: CharacterParser {\n        \n        let parsers = asciiCodesMap.map { control in\n            \n            StrParser.string(control.esc) *> GenericParser(result: control.code)\n            \n        }\n        \n        return GenericParser.choice(parsers)\n        \n    }\n    \n    private static var charControl: CharacterParser {\n        \n        let upper = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n        let ctrlCodes: CharacterParser =\n            GenericParser.oneOf(upper).flatMap { char in\n                \n                let charA: Character = \"A\"\n                let value = char.unicodeScalar.value -\n                    charA.unicodeScalar.value + 1\n                let unicode = UnicodeScalar.fromUInt32(value)!\n                \n                return GenericParser(result: Character(unicode))\n                \n            }\n        \n        return GenericParser.character(\"^\") *> (ctrlCodes <|>\n            GenericParser.character(\"@\") *> GenericParser(result: \"\\0\") <|>\n            GenericParser.character(\"[\") *>\n            GenericParser(result: \"\\u{001B}\") <|>\n            GenericParser.character(\"]\") *>\n            GenericParser(result: \"\\u{001C}\") <|>\n            GenericParser.character(\"\\\\\") *>\n            GenericParser(result: \"\\u{001D}\") <|>\n            GenericParser.character(\"^\") *>\n            GenericParser(result: \"\\u{001E}\") <|>\n            GenericParser.character(\"_\") *> GenericParser(result: \"\\u{001F}\"))\n    }\n    \n    static func characterFromInt(_ v: Int) -> CharacterParser {\n        \n        guard let us = UnicodeScalar.fromInt(v) else {\n            \n            let outsideMsg = LocalizedString(\n                \"value outside of Unicode codespace\"\n            )\n            return GenericParser.fail(outsideMsg)\n            \n        }\n        \n        return GenericParser(result: Character(us))\n        \n    }\n    \n    private static func numberWithBase(\n        _ base: Int,\n        parser: CharacterParser\n    ) -> IntParser {\n        \n        return parser.many1 >>- { digits in\n            \n            return integerWithDigits(String(digits), base: base)\n            \n        }\n        \n    }\n    \n    static func integerWithDigits(_ digits: String, base: Int) -> IntParser {\n        \n        guard let integer = Int(digits, radix: base) else {\n            \n            let overflowMsg = LocalizedString(\"Int overflow\")\n            return GenericParser.fail(overflowMsg)\n            \n        }\n        \n        return GenericParser(result: integer)\n        \n    }\n    \n    private static func doubleWithBase(\n        _ base: Int,\n        parser: CharacterParser\n    ) -> DoubleParser {\n        \n        let baseDouble = Double(base)\n        \n        return parser.many1 >>- { digits in\n            \n            let double = digits.reduce(0.0) { acc, d in\n                \n                baseDouble * acc + Double(Int(String(d), radix: base)!)\n                \n            }\n            \n            return GenericParser(result: double)\n            \n        }\n        \n    }\n    \n    private static var doubleIntegerPart: DoubleParser {\n        \n        return GenericParser.decimalDigit.many1 >>- { digits in\n            \n            GenericParser(result: Double(String(digits))!)\n            \n        }\n        \n    }\n    \n    private static var naturalNumber: IntParser {\n        \n        let zeroNumber = GenericParser.character(\"0\") *>\n            (hexadecimal <|> octal <|> decimal <|> GenericParser(result: 0))\n            <?> \"\"\n        \n        return zeroNumber <|> decimal\n        \n    }\n    \n    private static func sign<Number: SignedNumeric>()\n        -> GenericParser<String, UserState, (Number) -> Number> {\n            \n        return GenericParser.character(\"-\") *> GenericParser(result: -) <|>\n            GenericParser.character(\"+\") *> GenericParser(result: { $0 }) <|>\n            GenericParser(result: { $0 })\n            \n    }\n    \n    private static func fractionalExponent(_ number: Double) -> DoubleParser {\n        \n        let fractionMsg = LocalizedString(\"fraction\")\n        \n        let fract = CharacterParser.character(\".\") *>\n            (GenericParser.decimalDigit.many1 <?> fractionMsg).map { digits in\n                \n                digits.reduceRight(0) { frac, digit in\n                    \n                    (frac + Double(String(digit))!) / 10\n                    \n                }\n                \n            }\n        \n        let exponentMsg = LocalizedString(\"exponent\")\n        \n        let expo = GenericParser.oneOf(\"eE\") *> sign() >>- { sign in\n            \n            (self.decimal <?> exponentMsg) >>- { exp in\n                \n                GenericParser(result: power(sign(exp)))\n                \n            }\n            \n        }\n        \n        let fraction = (fract <?> fractionMsg) >>- { frac in\n            \n            (expo <?> exponentMsg).otherwise(1) >>- { exp in\n                \n                return GenericParser(result: (number + frac) * exp)\n                \n            }\n            \n        }\n        \n        let exponent = expo >>- { exp in\n            \n            GenericParser(result: number * exp)\n            \n        }\n        \n        return fraction <|> exponent\n        \n    }\n    \n    private func caseString(_ name: String) -> StrParser {\n        \n        if languageDefinition.isCaseSensitive {\n            \n            return StrParser.string(name)\n            \n        }\n        \n        func walk(_ string: String) -> VoidParser {\n            \n            let unit = VoidParser(result: ())\n            \n            guard !string.isEmpty else { return unit }\n            \n            var str = string\n            let c = str.remove(at: str.startIndex)\n            \n            let charParser: VoidParser\n            if c.isAlpha {\n                \n                charParser = (GenericParser.character(c.lowercase) <|>\n                    GenericParser.character(c.uppercase)) *> unit\n                \n            } else {\n                \n                charParser = GenericParser.character(c) *> unit\n                \n            }\n            \n            return (charParser <?> name) >>- { _ in walk(str) }\n            \n        }\n        \n        return walk(name) *> GenericParser(result: name)\n        \n    }\n    \n}\n\nprivate let hexadecimalPrefixes = \"xX\"\nprivate let octalPrefixes = \"oO\"\n\nprivate let substituteCharacter: Character = \"\\u{001A}\"\n\nprivate let escapeMap: [(esc: Character, code: Character)] = [\n    (\"a\", \"\\u{0007}\"), (\"b\", \"\\u{0008}\"), (\"f\", \"\\u{000C}\"), (\"n\", \"\\n\"),\n    (\"r\", \"\\r\"), (\"t\", \"\\t\"), (\"v\", \"\\u{000B}\"), (\"\\\\\", \"\\\\\"), (\"\\\"\", \"\\\"\"),\n    (\"'\", \"'\")\n]\n\nprivate let asciiCodesMap: [(esc: String, code:Character)] = [\n    (\"NUL\", \"\\u{0000}\"), (\"SOH\", \"\\u{0001}\"), (\"STX\", \"\\u{0002}\"),\n    (\"ETX\", \"\\u{0003}\"), (\"EOT\", \"\\u{0004}\"), (\"ENQ\", \"\\u{0005}\"),\n    (\"ACK\", \"\\u{0006}\"), (\"BEL\", \"\\u{0007}\"), (\"BS\", \"\\u{0008}\"),\n    (\"HT\", \"\\u{0009}\"), (\"LF\", \"\\u{000A}\"), (\"VT\", \"\\u{000B}\"),\n    (\"FF\", \"\\u{000C}\"), (\"CR\", \"\\u{000D}\"), (\"SO\", \"\\u{000E}\"),\n    (\"SI\", \"\\u{000F}\"),  (\"DLE\", \"\\u{0010}\"), (\"DC1\", \"\\u{0011}\"),\n    (\"DC2\", \"\\u{0012}\"), (\"DC3\", \"\\u{0013}\"), (\"DC4\", \"\\u{0014}\"),\n    (\"NAK\", \"\\u{0015}\"), (\"SYN\", \"\\u{0016}\"), (\"ETB\", \"\\u{0017}\"),\n    (\"CAN\", \"\\u{0018}\"), (\"EM\", \"\\u{0019}\"), (\"SUB\", \"\\u{001A}\"),\n    (\"ESC\", \"\\u{001B}\"),  (\"FS\", \"\\u{001C}\"), (\"GS\", \"\\u{001D}\"),\n    (\"RS\", \"\\u{001E}\"), (\"US\", \"\\u{001F}\"), (\"SP\", \"\\u{0020}\"),\n    (\"DEL\", \"\\u{007F}\")\n]\n\nprivate func power(_ exp: Int) -> Double {\n    \n    if exp < 0 {\n        \n        return 1.0 / power(-exp)\n        \n    }\n    \n    return pow(10.0, Double(exp))\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/UInt16.swift",
    "content": "//==============================================================================\n// UInt16.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-11-22.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// UInt16 extension\n//==============================================================================\n\n//==============================================================================\n// Extension containing various utility methods related to characters.\nextension UInt16 {\n    \n    /// `true` if `self` is a single code unit.\n    var isSingleCodeUnit: Bool {\n        \n        return self >= 0x0000 && self <= 0xD7FF ||\n            self >= 0xE000 && self <= 0xFFFF\n        \n    }\n    \n}\n"
  },
  {
    "path": "Sources/SwiftParsec/UnicodeScalar.swift",
    "content": "//==============================================================================\n// UnicodeScalar.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-20.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//\n// UnicodeScalar extension\n//==============================================================================\n\n//==============================================================================\n// Extension containing various utility methods.\nextension UnicodeScalar {\n    \n    /// The maximum value for a code point.\n    static var max: Int { return 0x10FFFF }\n    \n    /// The minimum value for a code point.\n    static var min: Int { return 0 }\n    \n    /// Return a `UnicodeScalar` with value `v` or nil if the value is outside\n    /// of Unicode codespace or a surrogate pair code point.\n    ///\n    /// - parameter v: Unicode code point.\n    /// - returns: A `UnicodeScalar` with value `v` or nil if the value is\n    ///   outside of Unicode codespace or a surrogate pair code point.\n    static func fromInt(_ v: Int) -> UnicodeScalar? {\n        \n        guard v >= min && v <= max else { return nil }\n        \n        guard !isSurrogatePair(v) else { return nil }\n        \n        return UnicodeScalar(v)\n        \n    }\n    \n    /// Return a `UnicodeScalar` with value `v` or nil if the value is outside\n    /// of Unicode codespace.\n    ///\n    /// - parameter v: Unicode code point.\n    /// - returns: A `UnicodeScalar` with value `v` or nil if the value is\n    ///   outside of Unicode codespace.\n    static func fromUInt32(_ v: UInt32) -> UnicodeScalar? {\n        \n        guard v >= UInt32(min) && v <= UInt32(max) else { return nil }\n        \n        guard !isSurrogatePair(v) else { return nil }\n        \n        return UnicodeScalar(v)\n        \n    }\n    \n    private static func isSurrogatePair<T: BinaryInteger>(_ v: T) -> Bool {\n        \n        return v >= 0xD800 && v <= 0xDFFF\n        \n    }\n    \n}\n"
  },
  {
    "path": "SubmittingPatches.md",
    "content": "# Git Commit\n\nSome wise advice gathered from multiple sources on submitting patches.\n\n## Describe your changes\n\nDescribe your problem.  Whether your patch is a one-line bug fix or 5000 lines of a new feature, there must be an underlying problem that motivated you to do this work.\n\nDescribe user-visible impact.  Straight up crashes and lockups are pretty convincing, but not all bugs are that blatant.  Even if the problem was spotted during code review, describe the impact you think it can have on users.\n\nQuantify optimizations and trade-offs.  If you claim improvements in performance, memory consumption, stack footprint, or binary size, include numbers that back them up.  But also describe non-obvious costs.  Optimizations usually aren't free but trade-offs between CPU, memory, and readability; or, when it comes to heuristics, between different workloads.  Describe the expected downsides of your optimization so that the reviewer can weigh costs against benefits.\n\nOnce the problem is established, describe what you are actually doing about it in technical detail.  It's important to describe the change in plain English for the reviewer to verify that the code is behaving as you intend it to.\n\nThe maintainer will thank you if you write your patch description in a form which can be easily pulled into git, as a \"commit log”. Here’s a model Git commit message:\n\n> Capitalized, short (50 chars or less) summary\n>\n> More detailed explanatory text, if necessary. Wrap it to about 72  \n> characters or so. In some contexts, the first line is treated as the  \n> subject of an email and the rest of the text as the body. The blank  \n> line separating the summary from the body is critical (unless you omit  \n> the body entirely); tools like rebase can get confused if you run the  \n> two together.\n\nWrite your commit message in the imperative: \"Fix bug\" and not \"Fixed bug\"\nor \"Fixes bug.\" This convention matches up with commit messages generated\nby commands like git merge and git revert.\n\nFurther paragraphs come after blank lines.\n\n- Bullet points are okay, too\n\n- Typically a hyphen or asterisk is used for the bullet, followed by a\n  single space, with blank lines in between, but conventions vary here\n\n- Use a hanging indent\n\nSolve only one problem per patch.  If your description starts to get long, that's a sign that you probably need to split up your patch.\n\nDescribe your changes in imperative mood, e.g. \"make xyzzy do frotz” instead of \"[This patch] makes xyzzy do frotz\" or \"[I] changed xyzzy to do frotz\", as if you are giving orders to the codebase to change its behaviour.\n\nIf the patch fixes a logged bug entry, refer to that bug entry by number and URL.  If the patch follows from a mailing list discussion, give a URL to the mailing list archive.\n\nHowever, try to make your explanation understandable without external resources.  In addition to giving a URL to a mailing list archive or bug, summarize the relevant points of the discussion that led to the patch as submitted.\n\nIf you want to refer to a specific commit, don't just refer to the SHA-1 ID of the commit. Please also include the one-line summary of the commit, to make it easier for reviewers to know what it is about. Example:\n\n> Commit e21d2170f36602ae2708 (\"video: remove unnecessary  \n> platform_set_drvdata()\") removed the unnecessary  \n> platform_set_drvdata(), but left the variable \"dev\" unused,  \n> delete it.\n\nIf your patch fixes a bug in a specific commit, e.g. you found an issue using git-bisect, please use the 'Fixes:' tag with the first 12 characters of the SHA-1 ID, and the one line summary.  For example:\n\n> Fixes: e21d2170f366 (\"video: remove unnecessary platform_set_drvdata()”)\n\n## Separate your changes\n\nSeparate each **logical change** into a separate patch.\n\nFor example, if your changes include both bug fixes and performance enhancements for a single entity, separate those changes into two or more patches.  If your changes include an API update, and a addition which uses that new API, separate those into two patches.\n\nOn the other hand, if you make a single change to numerous files, group those changes into a single patch.  Thus a single logical change is contained within a single patch.\n\nThe point to remember is that each patch should make an easily understood change that can be verified by reviewers.  Each patch should be justifiable on its own merits.\n\nIf one patch depends on another patch in order for a change to be complete, that is OK.  Simply note \"this patch depends on patch X” in your patch description.\n\nWhen dividing your change into a series of patches, take special care to ensure that the program builds and runs properly after each patch in the series.  Developers using \"git bisect\" to track down a problem can end up splitting your patch series at any point; they will not thank you if you introduce bugs in the middle.\n\nSources:  \n<https://www.kernel.org/doc/Documentation/SubmittingPatches>  \n<https://github.com/torvalds/linux/pull/17#issuecomment-5659933>  \n<http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html>  \n<https://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message>\n"
  },
  {
    "path": "SwiftParsec.podspec",
    "content": "Pod::Spec.new do |s|\n  s.name = 'SwiftParsec'\n  s.version = '4.0.0'\n  s.license = '2-clause BSD'\n  s.summary = 'SwiftParsec is a Swift port of the Parsec parser combinator library.'\n  s.homepage = 'https://github.com/davedufresne/SwiftParsec'\n  s.authors = { 'David Dufresne' => 'https://github.com/davedufresne' }\n  s.source = { :git => 'https://github.com/davedufresne/SwiftParsec.git', :tag => s.version }\n\n  s.swift_version = '5.0'\n  s.ios.deployment_target = '9.0'\n  s.osx.deployment_target = '10.10'\n  s.tvos.deployment_target = '9.0'\n  s.watchos.deployment_target = '2.0'\n\n  s.source_files = 'Sources/SwiftParsec/*.swift'\nend\n"
  },
  {
    "path": "SwiftParsec.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 51;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t2FB9FE5A1E2C27A100957354 /* CharacterSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FB9FE591E2C27A100957354 /* CharacterSet.swift */; };\n\t\t2FB9FE5E1E2C280300957354 /* GenericTokenParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FB9FE5D1E2C280300957354 /* GenericTokenParser.swift */; };\n\t\t2FB9FE631E2C2AF800957354 /* GenericTokenParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FB9FE5F1E2C281000957354 /* GenericTokenParserTests.swift */; };\n\t\t2FB9FE641E2C2B0700957354 /* CharacterSetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2FB9FE5B1E2C27AE00957354 /* CharacterSetTests.swift */; };\n\t\t5703BE171BE4434F003FF5FA /* ExpressionParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5703BE161BE4434F003FF5FA /* ExpressionParserTests.swift */; };\n\t\t5703BE191BE6AC09003FF5FA /* Permutation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5703BE181BE6AC09003FF5FA /* Permutation.swift */; };\n\t\t5703BE1D1BEB9A4F003FF5FA /* PermutationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5703BE1C1BEB9A4F003FF5FA /* PermutationTests.swift */; };\n\t\t570B24891CD7F4400060E452 /* Parsec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 570B24881CD7F4400060E452 /* Parsec.swift */; };\n\t\t570DB5B51BC3422B0058D186 /* TokenParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 570DB5B41BC3422A0058D186 /* TokenParser.swift */; };\n\t\t5714D8C01BCEAE3B00FE4BF0 /* LanguageDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5714D8BF1BCEAE3A00FE4BF0 /* LanguageDefinition.swift */; };\n\t\t57167F0D1B99E66800F35A29 /* SwiftParsec.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57167F021B99E66800F35A29 /* SwiftParsec.framework */; };\n\t\t57167F121B99E66800F35A29 /* GenericParserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57167F111B99E66800F35A29 /* GenericParserTests.swift */; };\n\t\t57167F1D1B99E6E200F35A29 /* GenericParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57167F1C1B99E6E200F35A29 /* GenericParser.swift */; };\n\t\t57167F1F1B99EEA500F35A29 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57167F1E1B99EEA500F35A29 /* ParseError.swift */; };\n\t\t57167F211B99EF1300F35A29 /* Position.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57167F201B99EF1300F35A29 /* Position.swift */; };\n\t\t571730DC1BADEAB90073BBB7 /* CharacterMembership.swift in Sources */ = {isa = PBXBuildFile; fileRef = 571730DB1BADEAB90073BBB7 /* CharacterMembership.swift */; };\n\t\t57188DFB1D971048009634E0 /* CharacterConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57188DFA1D971048009634E0 /* CharacterConversion.swift */; };\n\t\t57188DFD1D9719CE009634E0 /* SequenceConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57188DFC1D9719CE009634E0 /* SequenceConversion.swift */; };\n\t\t571C73FC1BD6F3A60055B359 /* UnicodeScalar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 571C73FB1BD6F3A60055B359 /* UnicodeScalar.swift */; };\n\t\t5744A3A31D8EC52700CA7191 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5744A3A21D8EC52700CA7191 /* Either.swift */; };\n\t\t574A84961BAB598F008020BC /* CharacterParsersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 574A84951BAB598F008020BC /* CharacterParsersTests.swift */; };\n\t\t5768B5781BB0773A005FF951 /* TestUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5768B5771BB0773A005FF951 /* TestUtilities.swift */; };\n\t\t577261F81BE14A3700E70BEF /* ErrorMessageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 577261F71BE14A3700E70BEF /* ErrorMessageTest.swift */; };\n\t\t578435561BF66B3A0067B3E9 /* PositionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 578435551BF66B3A0067B3E9 /* PositionTests.swift */; };\n\t\t578E3B101CA4B014005B83B8 /* SwiftParsec.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 578E3B0F1CA4B014005B83B8 /* SwiftParsec.podspec */; };\n\t\t579C00C81C0277CA009282A6 /* UInt16.swift in Sources */ = {isa = PBXBuildFile; fileRef = 579C00C71C0277CA009282A6 /* UInt16.swift */; };\n\t\t579ED1211D3AE9C10078D6F4 /* JSONBenchmarkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 579ED1201D3AE9C10078D6F4 /* JSONBenchmarkTests.swift */; };\n\t\t57A86B0B1BC862CC00A7F45F /* CollectionAggregation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57A86B0A1BC862CC00A7F45F /* CollectionAggregation.swift */; };\n\t\t57A86B0D1BC983B400A7F45F /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57A86B0C1BC983B400A7F45F /* String.swift */; };\n\t\t57A86B0F1BC9990B00A7F45F /* SetAggregation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57A86B0E1BC9990B00A7F45F /* SetAggregation.swift */; };\n\t\t57AA4E011BB777FF0026DF01 /* CombinatorParsers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57AA4E001BB777FF0026DF01 /* CombinatorParsers.swift */; };\n\t\t57AA4E031BB77A0F0026DF01 /* CombinatorParsersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57AA4E021BB77A0F0026DF01 /* CombinatorParsersTests.swift */; };\n\t\t57ABA23C1CF5F39B00C2B657 /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57ABA23B1CF5F39B00C2B657 /* StringTests.swift */; };\n\t\t57C459781CE2150D0014764F /* UnicodeScalarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57C459771CE2150D0014764F /* UnicodeScalarTests.swift */; };\n\t\t57C956691BDAE01D00057A4F /* ExpressionParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57C956681BDAE01D00057A4F /* ExpressionParser.swift */; };\n\t\t57C995DB1CF86906000DA292 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57C995DA1CF86906000DA292 /* Configuration.swift */; };\n\t\t57CA68A51D4137D900726354 /* SampleJSON.json in Resources */ = {isa = PBXBuildFile; fileRef = 579ED1221D3AF4680078D6F4 /* SampleJSON.json */; };\n\t\t57E5A60B1BA36FD10062F479 /* RangeReplaceableCollectionInsertion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E5A60A1BA36FD10062F479 /* RangeReplaceableCollectionInsertion.swift */; };\n\t\t57E6F77F1BA7414B0015E875 /* SequenceAggregation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E6F77E1BA7414B0015E875 /* SequenceAggregation.swift */; };\n\t\t57E6F7831BAA1C260015E875 /* CharacterParsers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E6F7821BAA1C260015E875 /* CharacterParsers.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t57167F0E1B99E66800F35A29 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 57167EF91B99E66800F35A29 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 57167F011B99E66800F35A29;\n\t\t\tremoteInfo = SwiftParsec;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t2FB9FE591E2C27A100957354 /* CharacterSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterSet.swift; sourceTree = \"<group>\"; };\n\t\t2FB9FE5B1E2C27AE00957354 /* CharacterSetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterSetTests.swift; sourceTree = \"<group>\"; };\n\t\t2FB9FE5D1E2C280300957354 /* GenericTokenParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericTokenParser.swift; sourceTree = \"<group>\"; };\n\t\t2FB9FE5F1E2C281000957354 /* GenericTokenParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericTokenParserTests.swift; sourceTree = \"<group>\"; };\n\t\t5703BE161BE4434F003FF5FA /* ExpressionParserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpressionParserTests.swift; sourceTree = \"<group>\"; };\n\t\t5703BE181BE6AC09003FF5FA /* Permutation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Permutation.swift; sourceTree = \"<group>\"; };\n\t\t5703BE1C1BEB9A4F003FF5FA /* PermutationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PermutationTests.swift; sourceTree = \"<group>\"; };\n\t\t570B24881CD7F4400060E452 /* Parsec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parsec.swift; sourceTree = \"<group>\"; };\n\t\t570DB5B41BC3422A0058D186 /* TokenParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TokenParser.swift; sourceTree = \"<group>\"; };\n\t\t5714D8BF1BCEAE3A00FE4BF0 /* LanguageDefinition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LanguageDefinition.swift; sourceTree = \"<group>\"; };\n\t\t57167F021B99E66800F35A29 /* SwiftParsec.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SwiftParsec.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t57167F071B99E66800F35A29 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t57167F0C1B99E66800F35A29 /* SwiftParsecTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftParsecTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t57167F111B99E66800F35A29 /* GenericParserTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericParserTests.swift; sourceTree = \"<group>\"; };\n\t\t57167F131B99E66800F35A29 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t57167F1C1B99E6E200F35A29 /* GenericParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GenericParser.swift; sourceTree = \"<group>\"; };\n\t\t57167F1E1B99EEA500F35A29 /* ParseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseError.swift; sourceTree = \"<group>\"; };\n\t\t57167F201B99EF1300F35A29 /* Position.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Position.swift; sourceTree = \"<group>\"; };\n\t\t571730DB1BADEAB90073BBB7 /* CharacterMembership.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterMembership.swift; sourceTree = \"<group>\"; };\n\t\t57188DFA1D971048009634E0 /* CharacterConversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterConversion.swift; sourceTree = \"<group>\"; };\n\t\t57188DFC1D9719CE009634E0 /* SequenceConversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceConversion.swift; sourceTree = \"<group>\"; };\n\t\t571A4EFC1CE2895E00D6D446 /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = \"<group>\"; };\n\t\t571C73FB1BD6F3A60055B359 /* UnicodeScalar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnicodeScalar.swift; sourceTree = \"<group>\"; };\n\t\t5744A3A21D8EC52700CA7191 /* Either.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Either.swift; sourceTree = \"<group>\"; };\n\t\t574A84951BAB598F008020BC /* CharacterParsersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterParsersTests.swift; sourceTree = \"<group>\"; };\n\t\t575680E01CCA99E3003FBCFA /* SubmittingPatches.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = SubmittingPatches.md; sourceTree = \"<group>\"; };\n\t\t5768B5771BB0773A005FF951 /* TestUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestUtilities.swift; sourceTree = \"<group>\"; };\n\t\t577261F71BE14A3700E70BEF /* ErrorMessageTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorMessageTest.swift; sourceTree = \"<group>\"; };\n\t\t578435551BF66B3A0067B3E9 /* PositionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PositionTests.swift; sourceTree = \"<group>\"; };\n\t\t578435571BF692380067B3E9 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = \"<group>\"; };\n\t\t578E3B0F1CA4B014005B83B8 /* SwiftParsec.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SwiftParsec.podspec; sourceTree = \"<group>\"; };\n\t\t579C00C71C0277CA009282A6 /* UInt16.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UInt16.swift; sourceTree = \"<group>\"; };\n\t\t579C00CD1C03EC60009282A6 /* en.lproj */ = {isa = PBXFileReference; lastKnownFileType = folder; name = en.lproj; path = Sources/SwiftParsec/en.lproj; sourceTree = \"<group>\"; };\n\t\t579C00D31C03F16E009282A6 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\t579ED1201D3AE9C10078D6F4 /* JSONBenchmarkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONBenchmarkTests.swift; sourceTree = \"<group>\"; };\n\t\t579ED1221D3AF4680078D6F4 /* SampleJSON.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = SampleJSON.json; sourceTree = \"<group>\"; };\n\t\t57A86B0A1BC862CC00A7F45F /* CollectionAggregation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionAggregation.swift; sourceTree = \"<group>\"; };\n\t\t57A86B0C1BC983B400A7F45F /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = \"<group>\"; };\n\t\t57A86B0E1BC9990B00A7F45F /* SetAggregation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetAggregation.swift; sourceTree = \"<group>\"; };\n\t\t57AA4E001BB777FF0026DF01 /* CombinatorParsers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombinatorParsers.swift; sourceTree = \"<group>\"; };\n\t\t57AA4E021BB77A0F0026DF01 /* CombinatorParsersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombinatorParsersTests.swift; sourceTree = \"<group>\"; };\n\t\t57AB6BB51CF399E6008A1927 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = \"<group>\"; };\n\t\t57ABA23B1CF5F39B00C2B657 /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = \"<group>\"; };\n\t\t57BD79281E3D5961005E1BF0 /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LinuxMain.swift; path = Tests/LinuxMain.swift; sourceTree = \"<group>\"; };\n\t\t57C459771CE2150D0014764F /* UnicodeScalarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnicodeScalarTests.swift; sourceTree = \"<group>\"; };\n\t\t57C956681BDAE01D00057A4F /* ExpressionParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExpressionParser.swift; sourceTree = \"<group>\"; };\n\t\t57C995DA1CF86906000DA292 /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = \"<group>\"; };\n\t\t57D3AFF521FCF09500D1DCEF /* Release */ = {isa = PBXFileReference; lastKnownFileType = text; path = Release; sourceTree = \"<group>\"; };\n\t\t57E5A60A1BA36FD10062F479 /* RangeReplaceableCollectionInsertion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RangeReplaceableCollectionInsertion.swift; sourceTree = \"<group>\"; };\n\t\t57E6F77E1BA7414B0015E875 /* SequenceAggregation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceAggregation.swift; sourceTree = \"<group>\"; };\n\t\t57E6F7821BAA1C260015E875 /* CharacterParsers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CharacterParsers.swift; sourceTree = \"<group>\"; };\n\t\t57FA9BA81BB97463000DCC03 /* TODO */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TODO; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t57167EFE1B99E66800F35A29 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t57167F091B99E66800F35A29 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t57167F0D1B99E66800F35A29 /* SwiftParsec.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t57167EF81B99E66800F35A29 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t57167F041B99E66800F35A29 /* SwiftParsec */,\n\t\t\t\t57167F101B99E66800F35A29 /* SwiftParsecTests */,\n\t\t\t\t57167F031B99E66800F35A29 /* Products */,\n\t\t\t\t579C00CD1C03EC60009282A6 /* en.lproj */,\n\t\t\t\t571A4EFC1CE2895E00D6D446 /* CHANGELOG.md */,\n\t\t\t\t578435571BF692380067B3E9 /* LICENSE */,\n\t\t\t\t57BD79281E3D5961005E1BF0 /* LinuxMain.swift */,\n\t\t\t\t57AB6BB51CF399E6008A1927 /* Package.swift */,\n\t\t\t\t579C00D31C03F16E009282A6 /* README.md */,\n\t\t\t\t575680E01CCA99E3003FBCFA /* SubmittingPatches.md */,\n\t\t\t\t578E3B0F1CA4B014005B83B8 /* SwiftParsec.podspec */,\n\t\t\t\t57D3AFF521FCF09500D1DCEF /* Release */,\n\t\t\t\t57FA9BA81BB97463000DCC03 /* TODO */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t57167F031B99E66800F35A29 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t57167F021B99E66800F35A29 /* SwiftParsec.framework */,\n\t\t\t\t57167F0C1B99E66800F35A29 /* SwiftParsecTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t57167F041B99E66800F35A29 /* SwiftParsec */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t57E5A60E1BA372D40062F479 /* Extensions */,\n\t\t\t\t57E6F7821BAA1C260015E875 /* CharacterParsers.swift */,\n\t\t\t\t2FB9FE591E2C27A100957354 /* CharacterSet.swift */,\n\t\t\t\t57AA4E001BB777FF0026DF01 /* CombinatorParsers.swift */,\n\t\t\t\t57C995DA1CF86906000DA292 /* Configuration.swift */,\n\t\t\t\t5744A3A21D8EC52700CA7191 /* Either.swift */,\n\t\t\t\t57C956681BDAE01D00057A4F /* ExpressionParser.swift */,\n\t\t\t\t57167F1C1B99E6E200F35A29 /* GenericParser.swift */,\n\t\t\t\t2FB9FE5D1E2C280300957354 /* GenericTokenParser.swift */,\n\t\t\t\t5714D8BF1BCEAE3A00FE4BF0 /* LanguageDefinition.swift */,\n\t\t\t\t570B24881CD7F4400060E452 /* Parsec.swift */,\n\t\t\t\t57167F1E1B99EEA500F35A29 /* ParseError.swift */,\n\t\t\t\t5703BE181BE6AC09003FF5FA /* Permutation.swift */,\n\t\t\t\t57167F201B99EF1300F35A29 /* Position.swift */,\n\t\t\t\t570DB5B41BC3422A0058D186 /* TokenParser.swift */,\n\t\t\t\t57167F071B99E66800F35A29 /* Info.plist */,\n\t\t\t);\n\t\t\tname = SwiftParsec;\n\t\t\tpath = Sources/SwiftParsec;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t57167F101B99E66800F35A29 /* SwiftParsecTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t574A84951BAB598F008020BC /* CharacterParsersTests.swift */,\n\t\t\t\t2FB9FE5B1E2C27AE00957354 /* CharacterSetTests.swift */,\n\t\t\t\t57AA4E021BB77A0F0026DF01 /* CombinatorParsersTests.swift */,\n\t\t\t\t577261F71BE14A3700E70BEF /* ErrorMessageTest.swift */,\n\t\t\t\t5703BE161BE4434F003FF5FA /* ExpressionParserTests.swift */,\n\t\t\t\t57167F111B99E66800F35A29 /* GenericParserTests.swift */,\n\t\t\t\t2FB9FE5F1E2C281000957354 /* GenericTokenParserTests.swift */,\n\t\t\t\t579ED1201D3AE9C10078D6F4 /* JSONBenchmarkTests.swift */,\n\t\t\t\t5703BE1C1BEB9A4F003FF5FA /* PermutationTests.swift */,\n\t\t\t\t578435551BF66B3A0067B3E9 /* PositionTests.swift */,\n\t\t\t\t57ABA23B1CF5F39B00C2B657 /* StringTests.swift */,\n\t\t\t\t5768B5771BB0773A005FF951 /* TestUtilities.swift */,\n\t\t\t\t57C459771CE2150D0014764F /* UnicodeScalarTests.swift */,\n\t\t\t\t579ED1221D3AF4680078D6F4 /* SampleJSON.json */,\n\t\t\t\t57167F131B99E66800F35A29 /* Info.plist */,\n\t\t\t);\n\t\t\tname = SwiftParsecTests;\n\t\t\tpath = Tests/SwiftParsecTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t57E5A60E1BA372D40062F479 /* Extensions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t57188DFA1D971048009634E0 /* CharacterConversion.swift */,\n\t\t\t\t571730DB1BADEAB90073BBB7 /* CharacterMembership.swift */,\n\t\t\t\t57A86B0A1BC862CC00A7F45F /* CollectionAggregation.swift */,\n\t\t\t\t57E5A60A1BA36FD10062F479 /* RangeReplaceableCollectionInsertion.swift */,\n\t\t\t\t57E6F77E1BA7414B0015E875 /* SequenceAggregation.swift */,\n\t\t\t\t57188DFC1D9719CE009634E0 /* SequenceConversion.swift */,\n\t\t\t\t57A86B0E1BC9990B00A7F45F /* SetAggregation.swift */,\n\t\t\t\t57A86B0C1BC983B400A7F45F /* String.swift */,\n\t\t\t\t579C00C71C0277CA009282A6 /* UInt16.swift */,\n\t\t\t\t571C73FB1BD6F3A60055B359 /* UnicodeScalar.swift */,\n\t\t\t);\n\t\t\tname = Extensions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t57167EFF1B99E66800F35A29 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\t57167F011B99E66800F35A29 /* SwiftParsec */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 57167F161B99E66800F35A29 /* Build configuration list for PBXNativeTarget \"SwiftParsec\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t57167EFD1B99E66800F35A29 /* Sources */,\n\t\t\t\t57167EFE1B99E66800F35A29 /* Frameworks */,\n\t\t\t\t57167EFF1B99E66800F35A29 /* Headers */,\n\t\t\t\t57167F001B99E66800F35A29 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = SwiftParsec;\n\t\t\tproductName = SwiftParsec;\n\t\t\tproductReference = 57167F021B99E66800F35A29 /* SwiftParsec.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t57167F0B1B99E66800F35A29 /* SwiftParsecTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 57167F191B99E66800F35A29 /* Build configuration list for PBXNativeTarget \"SwiftParsecTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t57167F081B99E66800F35A29 /* Sources */,\n\t\t\t\t57167F091B99E66800F35A29 /* Frameworks */,\n\t\t\t\t57167F0A1B99E66800F35A29 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t57167F0F1B99E66800F35A29 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = SwiftParsecTests;\n\t\t\tproductName = SwiftParsecTests;\n\t\t\tproductReference = 57167F0C1B99E66800F35A29 /* SwiftParsecTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t57167EF91B99E66800F35A29 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 0700;\n\t\t\t\tLastUpgradeCheck = 1210;\n\t\t\t\tORGANIZATIONNAME = \"David Dufresne\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t57167F011B99E66800F35A29 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.0;\n\t\t\t\t\t\tLastSwiftMigration = 1140;\n\t\t\t\t\t};\n\t\t\t\t\t57167F0B1B99E66800F35A29 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 7.0;\n\t\t\t\t\t\tLastSwiftMigration = 1140;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 57167EFC1B99E66800F35A29 /* Build configuration list for PBXProject \"SwiftParsec\" */;\n\t\t\tcompatibilityVersion = \"Xcode 10.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 57167EF81B99E66800F35A29;\n\t\t\tproductRefGroup = 57167F031B99E66800F35A29 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t57167F011B99E66800F35A29 /* SwiftParsec */,\n\t\t\t\t57167F0B1B99E66800F35A29 /* SwiftParsecTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t57167F001B99E66800F35A29 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t578E3B101CA4B014005B83B8 /* SwiftParsec.podspec in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t57167F0A1B99E66800F35A29 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t57CA68A51D4137D900726354 /* SampleJSON.json in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t57167EFD1B99E66800F35A29 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t570DB5B51BC3422B0058D186 /* TokenParser.swift in Sources */,\n\t\t\t\t570B24891CD7F4400060E452 /* Parsec.swift in Sources */,\n\t\t\t\t57E6F77F1BA7414B0015E875 /* SequenceAggregation.swift in Sources */,\n\t\t\t\t57C995DB1CF86906000DA292 /* Configuration.swift in Sources */,\n\t\t\t\t5744A3A31D8EC52700CA7191 /* Either.swift in Sources */,\n\t\t\t\t57AA4E011BB777FF0026DF01 /* CombinatorParsers.swift in Sources */,\n\t\t\t\t5714D8C01BCEAE3B00FE4BF0 /* LanguageDefinition.swift in Sources */,\n\t\t\t\t579C00C81C0277CA009282A6 /* UInt16.swift in Sources */,\n\t\t\t\t57188DFB1D971048009634E0 /* CharacterConversion.swift in Sources */,\n\t\t\t\t57167F1F1B99EEA500F35A29 /* ParseError.swift in Sources */,\n\t\t\t\t57167F1D1B99E6E200F35A29 /* GenericParser.swift in Sources */,\n\t\t\t\t57A86B0B1BC862CC00A7F45F /* CollectionAggregation.swift in Sources */,\n\t\t\t\t57188DFD1D9719CE009634E0 /* SequenceConversion.swift in Sources */,\n\t\t\t\t571730DC1BADEAB90073BBB7 /* CharacterMembership.swift in Sources */,\n\t\t\t\t57E6F7831BAA1C260015E875 /* CharacterParsers.swift in Sources */,\n\t\t\t\t57167F211B99EF1300F35A29 /* Position.swift in Sources */,\n\t\t\t\t2FB9FE5E1E2C280300957354 /* GenericTokenParser.swift in Sources */,\n\t\t\t\t57C956691BDAE01D00057A4F /* ExpressionParser.swift in Sources */,\n\t\t\t\t57A86B0D1BC983B400A7F45F /* String.swift in Sources */,\n\t\t\t\t2FB9FE5A1E2C27A100957354 /* CharacterSet.swift in Sources */,\n\t\t\t\t57A86B0F1BC9990B00A7F45F /* SetAggregation.swift in Sources */,\n\t\t\t\t571C73FC1BD6F3A60055B359 /* UnicodeScalar.swift in Sources */,\n\t\t\t\t5703BE191BE6AC09003FF5FA /* Permutation.swift in Sources */,\n\t\t\t\t57E5A60B1BA36FD10062F479 /* RangeReplaceableCollectionInsertion.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t57167F081B99E66800F35A29 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t5768B5781BB0773A005FF951 /* TestUtilities.swift in Sources */,\n\t\t\t\t577261F81BE14A3700E70BEF /* ErrorMessageTest.swift in Sources */,\n\t\t\t\t57AA4E031BB77A0F0026DF01 /* CombinatorParsersTests.swift in Sources */,\n\t\t\t\t57ABA23C1CF5F39B00C2B657 /* StringTests.swift in Sources */,\n\t\t\t\t5703BE1D1BEB9A4F003FF5FA /* PermutationTests.swift in Sources */,\n\t\t\t\t57167F121B99E66800F35A29 /* GenericParserTests.swift in Sources */,\n\t\t\t\t2FB9FE641E2C2B0700957354 /* CharacterSetTests.swift in Sources */,\n\t\t\t\t578435561BF66B3A0067B3E9 /* PositionTests.swift in Sources */,\n\t\t\t\t574A84961BAB598F008020BC /* CharacterParsersTests.swift in Sources */,\n\t\t\t\t579ED1211D3AE9C10078D6F4 /* JSONBenchmarkTests.swift in Sources */,\n\t\t\t\t5703BE171BE4434F003FF5FA /* ExpressionParserTests.swift in Sources */,\n\t\t\t\t2FB9FE631E2C2AF800957354 /* GenericTokenParserTests.swift in Sources */,\n\t\t\t\t57C459781CE2150D0014764F /* UnicodeScalarTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t57167F0F1B99E66800F35A29 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 57167F011B99E66800F35A29 /* SwiftParsec */;\n\t\t\ttargetProxy = 57167F0E1B99E66800F35A29 /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin XCBuildConfiguration section */\n\t\t57167F141B99E66800F35A29 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t57167F151B99E66800F35A29 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++0x\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\" = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu99;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t57167F171B99E66800F35A29 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tINFOPLIST_FILE = Sources/SwiftParsec/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tMARKETING_VERSION = 4.0.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = daviddufresne.SwiftParsec;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos macosx\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Default;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVALID_ARCHS = \"arm64 armv7 armv7s i386 x86_64\";\n\t\t\t\t\"VALID_ARCHS[sdk=*]\" = \"arm64 armv7 armv7s i368 x86_64\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t57167F181B99E66800F35A29 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tINFOPLIST_FILE = Sources/SwiftParsec/Info.plist;\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.11;\n\t\t\t\tMARKETING_VERSION = 4.0.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = daviddufresne.SwiftParsec;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos macosx\";\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Default;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVALID_ARCHS = \"arm64 armv7 armv7s i386 x86_64\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t57167F1A1B99E66800F35A29 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Tests/SwiftParsecTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = daviddufresne.SwiftParsecTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos macosx\";\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Default;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVALID_ARCHS = \"arm64 armv7 armv7s i386 x86_64\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t57167F1B1B99E66800F35A29 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tFRAMEWORK_SEARCH_PATHS = (\n\t\t\t\t\t\"$(SDKROOT)\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tINFOPLIST_FILE = Tests/SwiftParsecTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = daviddufresne.SwiftParsecTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSUPPORTED_PLATFORMS = \"iphonesimulator iphoneos macosx\";\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Default;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tVALID_ARCHS = \"arm64 armv7 armv7s i386 x86_64\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t57167EFC1B99E66800F35A29 /* Build configuration list for PBXProject \"SwiftParsec\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t57167F141B99E66800F35A29 /* Debug */,\n\t\t\t\t57167F151B99E66800F35A29 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t57167F161B99E66800F35A29 /* Build configuration list for PBXNativeTarget \"SwiftParsec\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t57167F171B99E66800F35A29 /* Debug */,\n\t\t\t\t57167F181B99E66800F35A29 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t57167F191B99E66800F35A29 /* Build configuration list for PBXNativeTarget \"SwiftParsecTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t57167F1A1B99E66800F35A29 /* Debug */,\n\t\t\t\t57167F1B1B99E66800F35A29 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 57167EF91B99E66800F35A29 /* Project object */;\n}\n"
  },
  {
    "path": "SwiftParsec.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:SwiftParsec.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "SwiftParsec.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "SwiftParsec.xcodeproj/xcshareddata/xcschemes/SwiftParsec.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1210\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"57167F011B99E66800F35A29\"\n               BuildableName = \"SwiftParsec.framework\"\n               BlueprintName = \"SwiftParsec\"\n               ReferencedContainer = \"container:SwiftParsec.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      codeCoverageEnabled = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"57167F011B99E66800F35A29\"\n            BuildableName = \"SwiftParsec.framework\"\n            BlueprintName = \"SwiftParsec\"\n            ReferencedContainer = \"container:SwiftParsec.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"57167F0B1B99E66800F35A29\"\n               BuildableName = \"SwiftParsecTests.xctest\"\n               BlueprintName = \"SwiftParsecTests\"\n               ReferencedContainer = \"container:SwiftParsec.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"57167F011B99E66800F35A29\"\n            BuildableName = \"SwiftParsec.framework\"\n            BlueprintName = \"SwiftParsec\"\n            ReferencedContainer = \"container:SwiftParsec.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"57167F011B99E66800F35A29\"\n            BuildableName = \"SwiftParsec.framework\"\n            BlueprintName = \"SwiftParsec\"\n            ReferencedContainer = \"container:SwiftParsec.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Tests/LinuxMain.swift",
    "content": "import XCTest\n@testable import SwiftParsecTests\n\nXCTMain([\n    testCase(CharacterParsersTests.allTests),\n    testCase(CharacterSetTests.allTests),\n    testCase(CombinatorParsersTests.allTests),\n    testCase(ErrorMessageTests.allTests),\n    testCase(ExpressionParserTests.allTests),\n    testCase(GenericParserTests.allTests),\n    testCase(GenericTokenParserTests.allTests),\n    testCase(JSONBenchmarkTests.allTests),\n    testCase(PermutationTests.allTests),\n    testCase(PositionTests.allTests),\n    testCase(StringTests.allTests),\n    testCase(UnicodeScalarTests.allTests)\n])\n"
  },
  {
    "path": "Tests/SwiftParsecTests/CharacterParsersTests.swift",
    "content": "//==============================================================================\n// CharacterParsersTests.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-17.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nclass CharacterParsersTests: XCTestCase {\n    \n    func testOneOf() {\n        \n        let vowel = StringParser.oneOf(\"aeiou\")\n        \n        // Test for success.\n        let matching = [\"axyz\", \"exyz\", \"ixyz\", \"oxyz\", \"uxyz\"]\n        let errorMessage = \"GenericParser.oneOf should succeed.\"\n        \n        testStringParserSuccess(vowel, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test for failure.\n        let notMatching = [\"xyzu\", \"yzo\", \"zi\", \"taeiou\", \"vexyz\"]\n        let shouldFailMessage = \"GenericParser.oneOf should fail.\"\n        \n        testStringParserFailure(vowel, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testOneOfInterval() {\n        \n        let interval = StringParser.oneOf(\"a\"...\"z\")\n        \n        // Test for success.\n        let matching = [\"axyz\", \"exyz\", \"ixyz\", \"oxyz\", \"uxyz\"]\n        let errorMessage = \"GenericParser.oneOf should succeed.\"\n        \n        testStringParserSuccess(interval, inputs: matching) { input, result in\n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test for failure.\n        let notMatching = [\"1xyzu\", \"?yzo\", \"Ezi\", \")taeiou\", \"@vexyz\"]\n        let shouldFailMessage = \"GenericParser.oneOf should fail.\"\n        \n        testStringParserFailure(interval, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(self.formatErrorMessage(\n                shouldFailMessage,\n                input: input,\n                result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testNoneOf() {\n        \n        let consonant = StringParser.noneOf(\"aeiou\")\n        \n        // Test for success.\n        let matching = [\"xayz\", \"reyz\", \"fiyz\", \"doyz\", \"cuyz\"]\n        let errorMessage = \"GenericParser.noneOf should succeed.\"\n        \n        testStringParserSuccess(consonant, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test for failure.\n        let notMatching = [\"axyz\", \"exyz\", \"ixyz\", \"oxyz\", \"uxyz\"]\n        let shouldFailMessage = \"GenericParser.noneOf should fail.\"\n        \n        testStringParserFailure(consonant, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testSpaces() {\n        \n        let suffix = \"xadf\"\n        let skipSpaces = StringParser.spaces *>\n            StringParser.character(suffix[suffix.startIndex])\n        \n        // Test for success.\n        let matching = [\"  \\n  \\t \\r \\r\\n\" + suffix]\n        let errorMessage = \"GenericParser.spaces should succeed.\"\n        \n        testStringParserSuccess(skipSpaces, inputs: matching) { input, result in\n            \n            let isMatch = suffix.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"axyz\", \"exyz\", \"ixyz\", \"oxyz\", \"uxyz\"]\n        let shouldFailMessage = \"GenericParser.spaces should fail.\"\n        \n        testStringParserFailure(skipSpaces, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testUnicodeSpace() {\n        \n        let space = StringParser.unicodeSpace\n        \n        // Test for success.\n        let matching = [\n            \" xadf\", \"\\tljk\", \"\\n;k\", \"\\r;kl\", \"\\r\\nadf\", \"\\u{000C}jkl\",\n            \"\\u{000B}gjh\", \"\\u{0085}jg\", \"\\u{00A0}gj\", \"\\u{1680}\", \"\\u{180E}\",\n            \"\\u{2000}\", \"\\u{2001}\", \"\\u{2002}\", \"\\u{2003}\", \"\\u{2004}\",\n            \"\\u{2005}\", \"\\u{2006}\", \"\\u{2007}\", \"\\u{2008}\", \"\\u{2009}\",\n            \"\\u{200A}\", \"\\u{200B}fhd\", \"\\u{2028}\", \"\\u{2029}\", \"\\u{202F}ghfd\",\n            \"\\u{205F}gh\",  \"\\u{3000}hjg\", \"\\u{FEFF}kgh\"\n        ]\n        let errorMessage = \"GenericParser.unicodeSpace should succeed.\"\n        \n        testStringParserSuccess(space, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"axyz   \"]\n        let shouldFailMessage = \"GenericParser.unicodeSpace should fail.\"\n        \n        testStringParserFailure(space, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testSpace() {\n        \n        let space = StringParser.space\n        \n        // Test for success.\n        let matching = [\n            \" xadf\", \"\\tljk\", \"\\n;k\", \"\\r;kl\", \"\\r\\nadf\", \"\\u{000C}jkl\",\n            \"\\u{000B}gjh\"\n        ]\n        let errorMessage = \"GenericParser.space should succeed.\"\n        \n        testStringParserSuccess(space, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"axyz   \"]\n        let shouldFailMessage = \"GenericParser.space should fail.\"\n        \n        testStringParserFailure(space, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testNewLine() {\n        \n        let newLine = StringParser.newLine\n        \n        // Test for success.\n        let matching = [\"\\n\"]\n        let errorMessage = \"GenericParser.newLine should succeed.\"\n        \n        testStringParserSuccess(newLine, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"axyz\\n\"]\n        let shouldFailMessage = \"GenericParser.newLine should fail.\"\n        \n        testStringParserFailure(newLine, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testCrlf() {\n        \n        let newLine = StringParser.crlf\n        \n        // Test for success.\n        // \"\\r\\n\" is combined in one Unicode Scalar.\n        let matching = [\"\\r\\n\", \"\\u{000D}\\u{000A}\"]\n        let errorMessage = \"GenericParser.crlf should succeed.\"\n        \n        testStringParserSuccess(newLine, inputs: matching) { input, result in\n            \n            XCTAssertEqual(\n                \"\\n\",\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"\\n\", \"\\r\", \"\\n\\r\", \"adsf\\r\\n\"]\n        let shouldFailMessage = \"GenericParser.crlf should fail.\"\n        \n        testStringParserFailure(newLine, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testEndOfLine() {\n        \n        let endOfLine = StringParser.endOfLine\n        \n        // Test for success.\n        // \"\\r\\n\" is combined in one Unicode Scalar.\n        let matching = [\"\\r\\n\", \"\\u{000D}\\u{000A}\", \"\\n\"]\n        let errorMessage = \"GenericParser.endOfLine should succeed.\"\n        \n        testStringParserSuccess(endOfLine, inputs: matching) { input, result in\n            \n            XCTAssertEqual(\n                \"\\n\",\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"\\r\", \"ddsdf\\n\\r\", \"adsf\\r\\n\", \"adsf'\\n\"]\n        let shouldFailMessage = \"GenericParser.endOfLine should fail.\"\n        \n        testStringParserFailure(endOfLine, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testTab() {\n        \n        let tab = StringParser.tab\n        \n        // Test for success.\n        let matching = [\"\\t\"]\n        let errorMessage = \"GenericParser.tab should succeed.\"\n        \n        testStringParserSuccess(tab, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"axyz\\t\"]\n        let shouldFailMessage = \"GenericParser.tab should fail.\"\n        \n        testStringParserFailure(tab, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testUppercase() {\n        \n        let uppercase = StringParser.uppercase\n        \n        // Test for success.\n        let matching = [\"Ezcxv\", \"A\", \"À\", \"Ç\", \"É\", \"È\", \"Ë\", \"Ê\", \"Ùaff\"]\n        let errorMessage = \"GenericParser.uppercase should succeed.\"\n        \n        testStringParserSuccess(uppercase, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"easdf\", \"a\", \"à\", \"ç\", \"é\", \"è\", \"ê\", \"ùasdf\", \";\", \":\", \",\"\n        ]\n        let shouldFailMessage = \"GenericParser.uppercase should fail.\"\n        \n        testStringParserFailure(uppercase, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testLowercase() {\n        \n        let lowercase = StringParser.lowercase\n        \n        // Test for success.\n        let matching = [\"easdf\", \"a\", \"à\", \"ç\", \"é\", \"è\", \"ê\", \"ùasdf\"]\n        let errorMessage = \"GenericParser.lowercase should succeed.\"\n        \n        testStringParserSuccess(lowercase, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"Ezcxv\", \"A\", \"À\", \"Ç\", \"É\", \"È\", \"Ë\", \"Ê\", \"Ùaff\", \";\", \":\", \",\"\n        ]\n        let shouldFailMessage = \"GenericParser.lowercase should fail.\"\n        \n        testStringParserFailure(lowercase, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testAlphaNumeric() {\n        \n        let alphaNum = StringParser.alphaNumeric\n        \n        // Test for success.\n        let matching = [\n            \"easdf\", \"a\", \"à\", \"ç\", \"é\", \"\\u{65}\\u{301}\", \"è\", \"ê\", \"ùasdf\",\n            \"Ezcxv\", \"A\", \"À\", \"Ç\", \"É\", \"È\", \"Ë\", \"Ê\", \"Ùaff\", \"1\", \"2\", \"3\",\n            \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\"\n        ]\n        let errorMessage = \"GenericParser.alphaNumeric should succeed.\"\n        \n        testStringParserSuccess(alphaNum, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \";\", \":\", \",\", \"\\t\", \"\\r\\n\", \"\\u{000D}\\u{000A}\", \"\\n\", \"+\", \"±\",\n            \"!\", \"@\", \"#\", \"$\", \"%\", \"^\", \"&\", \"*\", \"(\", \")\", \"-\", \"=\", \"}\",\n            \"{\", \"<\", \">\", \"?\", \"\\u{E9}\\u{20DD}\"\n        ]\n        let shouldFailMessage = \"GenericParser.alphaNumeric should fail.\"\n        \n        testStringParserFailure(alphaNum, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testLetter() {\n        \n        let letter = StringParser.letter\n        \n        // Test for success.\n        let matching = [\n            \"easdf\", \"a\", \"à\", \"ç\", \"é\", \"è\", \"ê\", \"ùasdf\", \"Ezcxv\", \"A\", \"À\",\n            \"Ç\", \"É\", \"È\", \"Ë\", \"Ê\", \"Ùaff\"\n        ]\n        let errorMessage = \"GenericParser.letter should succeed.\"\n        \n        testStringParserSuccess(letter, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \";\", \":\", \",\", \"\\t\", \"\\r\\n\", \"\\u{000D}\\u{000A}\", \"\\n\", \"+\", \"±\",\n            \"!\", \"@\", \"#\", \"$\", \"%\", \"^\", \"&\", \"*\", \"(\", \")\", \"-\", \"=\", \"}\",\n            \"{\", \"<\", \">\", \"?\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\"\n        ]\n        let shouldFailMessage = \"GenericParser.letter should fail.\"\n        \n        testStringParserFailure(letter, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testSymbol() {\n        \n        let symbol = StringParser.symbol\n        \n        // Test for success.\n        let matching = [\"+\", \"÷\", \"±\", \"$\", \"√\"]\n        let errorMessage = \"GenericParser.symbol should succeed.\"\n        \n        testStringParserSuccess(symbol, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"easdf\", \"a\", \"à\", \"ç\", \"é\", \"è\", \"ê\", \"ùasdf\", \"Ezcxv\", \"A\", \"À\",\n            \"Ç\", \"É\", \"È\", \"Ë\", \"Ê\", \"Ùaff\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\",\n            \"8\", \"9\", \"0\"\n        ]\n        let shouldFailMessage = \"GenericParser.letter should fail.\"\n        \n        testStringParserFailure(symbol, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testDigit() {\n        \n        let digit = StringParser.digit\n        \n        // Test for success.\n        let matching = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\"]\n        let errorMessage = \"GenericParser.digit should succeed.\"\n        \n        testStringParserSuccess(digit, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \";\", \":\", \",\", \"\\t\", \"\\r\\n\", \"\\u{000D}\\u{000A}\", \"\\n\", \"+\", \"±\",\n            \"!\", \"@\", \"#\", \"$\", \"%\", \"^\", \"&\", \"*\", \"(\", \")\", \"-\", \"=\", \"}\",\n            \"{\", \"<\", \">\", \"?\", \"easdf\", \"a\", \"à\", \"ç\", \"é\", \"è\", \"ê\", \"ùasdf\",\n            \"Ezcxv\", \"A\", \"À\", \"Ç\", \"É\", \"È\", \"Ë\", \"Ê\", \"Ùaff\"\n        ]\n        let shouldFailMessage = \"GenericParser.digit should fail.\"\n        \n        testStringParserFailure(digit, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testDecimalDigit() {\n        \n        let hexDigit = StringParser.decimalDigit\n        \n        // Test for success.\n        let matching = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\"]\n        let errorMessage = \"GenericParser.decimalDigit should succeed.\"\n        \n        testStringParserSuccess(hexDigit, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \";\", \":\", \",\", \"\\t\", \"\\r\\n\", \"\\u{000D}\\u{000A}\", \"\\n\", \"+\", \"±\",\n            \"!\", \"@\", \"#\", \"$\", \"%\", \"^\", \"&\", \"*\", \"(\", \")\", \"-\", \"=\", \"}\",\n            \"{\", \"<\", \">\", \"?\", \"à\", \"ç\", \"é\", \"è\", \"ê\", \"ùasdf\", \"À\", \"Ç\", \"É\",\n            \"È\", \"Ë\", \"Ê\", \"Ùaff\", \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"A\", \"B\", \"C\",\n            \"D\", \"E\", \"F\"\n        ]\n        let shouldFailMessage = \"GenericParser.decimalDigit should fail.\"\n        \n        testStringParserFailure(hexDigit, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testHexadecimalDigit() {\n        \n        let hexDigit = StringParser.hexadecimalDigit\n        \n        // Test for success.\n        let matching = [\n            \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"0\", \"a\", \"b\", \"c\",\n            \"d\", \"e\", \"f\", \"A\", \"B\", \"C\", \"D\", \"E\", \"F\"\n        ]\n        let errorMessage = \"GenericParser.hexadecimalDigit should succeed.\"\n        \n        testStringParserSuccess(hexDigit, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \";\", \":\", \",\", \"\\t\", \"\\r\\n\", \"\\u{000D}\\u{000A}\", \"\\n\", \"+\", \"±\",\n            \"!\", \"@\", \"#\", \"$\", \"%\", \"^\", \"&\", \"*\", \"(\", \")\", \"-\", \"=\", \"}\",\n            \"{\", \"<\", \">\", \"?\", \"à\", \"ç\", \"é\", \"è\", \"ê\", \"ùasdf\", \"À\", \"Ç\", \"É\",\n            \"È\", \"Ë\", \"Ê\", \"Ùaff\"\n        ]\n        \n        let shouldFailMessage =\n        \"GenericParser.hexadecimalDigit should fail.\"\n        \n        testStringParserFailure(hexDigit, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testOctalDigit() {\n        \n        let octDigit = StringParser.octalDigit\n        \n        // Test for success.\n        let matching = [\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"0\"]\n        let errorMessage = \"GenericParser.octalDigit should succeed.\"\n        \n        testStringParserSuccess(octDigit, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \";\", \":\", \",\", \"\\t\", \"\\r\\n\", \"\\u{000D}\\u{000A}\", \"\\n\", \"+\", \"±\",\n            \"!\", \"@\", \"#\", \"$\", \"%\", \"^\", \"&\", \"*\", \"(\", \")\", \"-\", \"=\", \"}\",\n            \"{\", \"<\", \">\", \"?\", \"à\", \"ç\", \"é\", \"è\", \"ê\", \"ùasdf\", \"À\", \"Ç\", \"É\",\n            \"È\", \"Ë\", \"Ê\", \"Ùaff\", \"8\", \"9\"\n        ]\n        let shouldFailMessage = \"GenericParser.octalDigit should fail.\"\n        \n        testStringParserFailure(octDigit, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testString() {\n        \n        let stringToMatch = \"aàeéèëcçAÀEÉÈËCÇ\"\n        let string1 = StringParser.string(stringToMatch)\n        \n        // Test for success.\n        let matching = [stringToMatch + \"qewr\", stringToMatch]\n        let errorMessage = \"GenericParser.string should succeed.\"\n        \n        testStringParserSuccess(string1, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(result)\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"àaeéèëcçAÀEÉÈËCÇ\",\n            String(stringToMatch.dropLast())\n        ]\n        let shouldFailMessage = \"GenericParser.string should fail.\"\n        \n        testStringParserFailure(string1, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test for success with empty string to match.\n        let string2 = StringParser.string(\"\")\n        testStringParserSuccess(string2, inputs: [\"\", \"adsf\"])\n        { input, result in\n            \n            XCTAssert(\n                result.isEmpty,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n}\n\nextension CharacterParsersTests {\n    static var allTests:\n    [(String, (CharacterParsersTests) -> () throws -> Void)] {\n        return [\n            (\"testOneOf\", testOneOf),\n            (\"testOneOfInterval\", testOneOfInterval),\n            (\"testNoneOf\", testNoneOf),\n            (\"testSpaces\", testSpaces),\n            (\"testUnicodeSpace\", testUnicodeSpace),\n            (\"testSpace\", testSpace),\n            (\"testNewLine\", testNewLine),\n            (\"testCrlf\", testCrlf),\n            (\"testEndOfLine\", testEndOfLine),\n            (\"testTab\", testTab),\n            (\"testUppercase\", testUppercase),\n            (\"testLowercase\", testLowercase),\n            (\"testAlphaNumeric\", testAlphaNumeric),\n            (\"testLetter\", testLetter),\n            (\"testSymbol\", testSymbol),\n            (\"testDigit\", testDigit),\n            (\"testDecimalDigit\", testDecimalDigit),\n            (\"testHexadecimalDigit\", testHexadecimalDigit),\n            (\"testOctalDigit\", testOctalDigit),\n            (\"testString\", testString)\n        ]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/CharacterSetTests.swift",
    "content": "//==============================================================================\n// CharacterSetTests.swift\n// SwiftParsec\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nclass CharacterSetTests: XCTestCase {\n    \n    // Creating large `Foundation.CharacterSet`s can cause Linux programs to\n    // halt (silently crash).\n    func testLarge() {\n        \n        // Initialized this way to overcome Swift 4.2 compiler error\n        let unicode: String = {\n            let strands: [String] = [\n                (0x10000...0x1FFFD).stringValue,\n                (0x20000...0x2FFFD).stringValue,\n                (0x30000...0x3FFFD).stringValue,\n                (0x40000...0x4FFFD).stringValue,\n                (0x50000...0x5FFFD).stringValue,\n                (0x60000...0x6FFFD).stringValue,\n                (0x70000...0x7FFFD).stringValue,\n                (0x80000...0x8FFFD).stringValue,\n                (0x90000...0x9FFFD).stringValue,\n                (0xA0000...0xAFFFD).stringValue,\n                (0xB0000...0xBFFFD).stringValue,\n                (0xC0000...0xCFFFD).stringValue,\n                (0xD0000...0xDFFFD).stringValue,\n                (0xE0000...0xEFFFD).stringValue\n            ]\n            return strands.reduce(into: \"\") { $0 += $1 }\n        }()\n        let _ = CharacterSet(charactersIn: unicode)\n    }\n    \n}\n\nextension CharacterSetTests {\n    static var allTests: [(String, (CharacterSetTests) -> () throws -> Void)] {\n        return [(\"testLarge\", testLarge)]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/CombinatorParsersTests.swift",
    "content": "//==============================================================================\n// CombinatorParsersTests.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-26.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\nimport func Foundation.pow\n@testable import SwiftParsec\n\nclass CombinatorParsersTests: XCTestCase {\n    \n    func testChoice() {\n        \n        let digit = StringParser.digit\n        let letter = StringParser.letter\n        let space = StringParser.space\n        \n        let parsers = [digit, letter, space]\n        let choice = StringParser.choice(parsers)\n        \n        // Test for success.\n        let matching = [\"1a \", \"a1 \", \" 1a\"]\n        \n        let errorMessage = \"GenericParser.choice should succeed.\"\n        \n        testStringParserSuccess(choice, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"\", \";1 a\", \"+a 1\"]\n        let shouldFailMessage = \"GenericParser.choice should fail.\"\n        \n        testStringParserFailure(choice, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testOtherwise() {\n        \n        let otherwiseDigit: Character = \"0\"\n        let digit = StringParser.digit.otherwise(otherwiseDigit)\n        \n        // Test for success.\n        let matchingDigit = [\"1a \", \"a1 \", \" 1a\"]\n        \n        let errorMessage = \"GenericParser.otherwise should succeed.\"\n        \n        testStringParserSuccess(digit, inputs: matchingDigit) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result)) ||\n                result == otherwiseDigit\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let otherwiseString = \"xyz\"\n        let string = StringParser.string(\"abc\").otherwise(otherwiseString)\n        \n        let matchingString = [\"abc\", \"123\"]\n        \n        testStringParserSuccess(string, inputs: matchingString)\n        { input, result in\n            \n            let isMatch = input.hasPrefix(result) || result == otherwiseString\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"ab1\", \"a12\"]\n        let shouldFailMessage = \"GenericParser.otherwise should fail.\"\n        \n        testStringParserFailure(string, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testOptional() {\n        \n        let optionalDigit = StringParser.digit.optional\n        \n        // Test for success.\n        let matchingDigit = [\"1a \", \"a1 \", \" 1a\"]\n        \n        let errorMessage = \"GenericParser.optional should succeed.\"\n        \n        testStringParserSuccess(optionalDigit, inputs: matchingDigit)\n        { input, result in\n            \n            let isMatch = result == nil || input.hasPrefix(String(result!))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let optionalString = StringParser.string(\"abc\").optional\n        \n        let matchingString = [\"abc\", \"123\"]\n        \n        testStringParserSuccess(optionalString, inputs: matchingString)\n        { input, result in\n            \n            let isMatch = result == nil || input.hasPrefix(result!)\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"ab1\", \"a12\"]\n        let shouldFailMessage = \"GenericParser.optional should fail.\"\n        \n        testStringParserFailure(optionalString, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testDiscard() {\n        \n        // Test for success.\n        let discardDigit = StringParser.digit.discard\n        let matchingDigit = [\"1a\", \"2b\", \"3c\"]\n        testStringParserSuccess(discardDigit, inputs: matchingDigit) { _, _ in }\n        \n        let discardString = StringParser.string(\"abc\").discard\n        let matchingString = [\"abc\", \"abc123\"]\n        testStringParserSuccess(discardString, inputs: matchingString)\n        { _, _ in }\n        \n        // Test when not matching.\n        let notMatching = [\"ab1\", \"a12\"]\n        let shouldFailMessage = \"GenericParser.discard should fail.\"\n        \n        testStringParserFailure(discardString, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testBetween() {\n        \n        let digitOpening = StringParser.character(\"(\")\n        let digitClosing = StringParser.character(\")\")\n        let digit = StringParser.digit.between(digitOpening, digitClosing)\n        \n        // Test for success.\n        let matchingDigit = [\"(1) \", \"(2)adsf\", \"(3)xfsa\"]\n        \n        let errorMessage = \"GenericParser.between should succeed.\"\n        \n        testStringParserSuccess(digit, inputs: matchingDigit)\n        { inputStr, result in\n            \n            let input = inputStr.dropFirst()\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: inputStr,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let stringOpening = StringParser.string(\"{[(\")\n        let stringClosing = StringParser.string(\")]}\")\n        let string =\n            StringParser.string(\"abc\").between(stringOpening, stringClosing)\n        \n        let matchingString = [\"{[(abc)]}\", \"{[(abc)]}abc\"]\n        \n        testStringParserSuccess(string, inputs: matchingString)\n        { inputStr, result in\n            \n            let startIndex = inputStr.startIndex\n            \n            var input = inputStr\n            input.removeSubrange(\n                startIndex..<inputStr.index(startIndex, offsetBy: 3)\n            )\n            \n            let isMatch = input.hasPrefix(result)\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: inputStr,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"{[(ab)]}\", \"{[(abc)]\", \"[(abc)]}\"]\n        let shouldFailMessage = \"GenericParser.between should fail.\"\n        \n        testStringParserFailure(string, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testSkipMany1() {\n        \n        let skipMany1 = StringParser.string(\"asdf\").skipMany1\n        \n        // Test for success.\n        let matching = [\"asdfasdf\", \"asdfasdfasdf\", \"asdfasdfasdfasdf\"]\n        \n        testStringParserSuccess(skipMany1, inputs: matching) { _, _ in }\n        \n        // Test when not matching.\n        let notMatching = [\"asd\", \"asdfasd\", \"xasdf\"]\n        let shouldFailMessage = \"GenericParser.skipMany1 should fail.\"\n        \n        testStringParserFailure(skipMany1, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testMany1() {\n        \n        let manyString = StringParser.string(\"asdf\").many1\n        \n        // Test for success.\n        let matching = [\"asdfasdf\", \"asdfasdfasdf\", \"asdfasdfasdfasdf\"]\n        let errorMessage = \"GenericParser.many1 should succeed.\"\n        \n        testStringParserSuccess(manyString, inputs: matching) { input, result in\n            \n            let isMatch = input == result.joined(separator: \"\")\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"asd\", \"asdfasd\", \"xasdf\"]\n        let shouldFailMessage = \"GenericParser.many1 should fail.\"\n        \n        testStringParserFailure(manyString, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testSeparatedBy() {\n        \n        let separator: Character = \",\"\n        \n        let comma = StringParser.character(separator)\n        let letters = StringParser.letter.many1.stringValue\n        let commaSeparated = letters.separatedBy(comma)\n        \n        // Test for success.\n        let matching = [\n            \"adsf\", \"asd,fasdÀf,qeàwr,dÉgéh\", \"234,adsf,erty\", \",adsf,zsdf\"\n        ]\n        \n        let errorMessage = \"GenericParser.separatedBy should succeed.\"\n        \n        testStringParserSuccess(commaSeparated, inputs: matching)\n        { input, result in\n            \n            let isMatch = result.isEmpty ||\n                result == input.components(separatedBy: String(separator))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"asd,,\", \"adsf,wert,1\"]\n        let shouldFailMessage = \"GenericParser.separatedBy should fail.\"\n        \n        testStringParserFailure(commaSeparated, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testSeparatedBy1() {\n        \n        let separator: Character = \",\"\n        \n        let comma = StringParser.character(separator)\n        let letters = StringParser.letter.many1.stringValue\n        let commaSeparated = letters.separatedBy1(comma)\n        \n        // Test for success.\n        let matching = [\"adsf\", \"asd,fasdÀf,qeàwr,dÉgéh\", \"adsf,zsdf\"]\n        \n        let errorMessage = \"GenericParser.separatedBy1 should succeed.\"\n        \n        testStringParserSuccess(commaSeparated, inputs: matching)\n        { input, result in\n            \n            let isMatch =\n                result == input.components(separatedBy: String(separator))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"asd,,\", \"adsf,wert,1\", \"234,adsf,erty\", \",adsf,zsdf\"\n        ]\n        let shouldFailMessage = \"GenericParser.separatedBy1 should fail.\"\n        \n        testStringParserFailure(commaSeparated, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testDividedBy() {\n        \n        let separator: Character = \",\"\n        \n        let comma = StringParser.character(separator)\n        let letters = StringParser.letter.many1.stringValue\n        let commaSeparated = letters.dividedBy(comma) <* StringParser.eof\n        \n        let errorMessage = \"GenericParser.dividedBy should succeed.\"\n        \n        // End separator required.\n        let endRequired = [\"adsf,\", \"asd,fasdÀf,qeàwr,dÉgéh,\"]\n        \n        testStringParserSuccess(commaSeparated, inputs: endRequired)\n        { input, result in\n            \n            let sep = String(separator)\n            let isMatch = result.isEmpty ||\n                result + [\"\"] == input.components(separatedBy: sep)\n            \n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // End separator not required\n        let commaDivided = letters.dividedBy(comma, endSeparatorRequired: false)\n            <* StringParser.eof\n        \n        let endNotRequired = [\n            \"adsf,\", \"asd,fasdÀf,qeàwr,dÉgéh,\", \"adsf\", \"asd,fasdÀf,qeàwr,dÉgéh\"\n        ]\n        \n        testStringParserSuccess(commaDivided, inputs: endNotRequired)\n        { input, result in\n            \n            let sep = String(separator)\n            let isEmpty = result.isEmpty\n            \n            let endNotPresentEqual =\n                result == input.components(separatedBy: sep)\n            let endPresentEqual =\n                result + [\"\"] == input.components(separatedBy: sep)\n            \n            let isMatch = isEmpty || endNotPresentEqual || endPresentEqual\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"adsf,wert,werb\", \"234,adsf,erty,\", \",adsf,zsdf,\"]\n        let shouldFailMessage = \"GenericParser.dividedBy should fail.\"\n        \n        testStringParserFailure(commaSeparated, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testDividedBy1() {\n        \n        let separator: Character = \",\"\n        \n        let comma = StringParser.character(separator)\n        let letters = StringParser.letter.many1.stringValue\n        let commaSeparated = letters.dividedBy1(comma)\n        \n        let errorMessage = \"GenericParser.dividedBy1 should succeed.\"\n        \n        // End separator required.\n        let endRequired = [\"adsf,\", \"asd,fasdÀf,qeàwr,dÉgéh,\"]\n        \n        testStringParserSuccess(commaSeparated, inputs: endRequired)\n        { input, result in\n            \n            let sep = String(separator)\n            let isMatch =\n                result + [\"\"] == input.components(separatedBy: sep)\n            \n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // End separator not required\n        let commaDivided =\n            letters.dividedBy1(comma, endSeparatorRequired: false)\n        \n        let endNotRequired = [\n            \"adsf,\", \"asd,fasdÀf,qeàwr,dÉgéh,\", \"adsf\", \"asd,fasdÀf,qeàwr,dÉgéh\"\n        ]\n        \n        testStringParserSuccess(commaDivided, inputs: endNotRequired)\n        { input, result in\n            \n            let sep = String(separator)\n            \n            let endNotPresentEqual =\n                result == input.components(separatedBy: sep)\n            let endPresentEqual =\n                result + [\"\"] == input.components(separatedBy: sep)\n            \n            let isMatch = endNotPresentEqual || endPresentEqual\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"adsf,wert,werb\", \",adsf,zsdf,\", \"234,adsf,erty,\"]\n        let shouldFailMessage = \"GenericParser.dividedBy1 should fail.\"\n        \n        testStringParserFailure(commaSeparated, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testCount() {\n        \n        let errorMessage = \"GenericParser.count should succeed.\"\n        \n        let countNumber = 3\n        let letters = StringParser.letter.many.stringValue.count(countNumber)\n        \n        // Test for success.\n        let matching = [\"adsf\", \"aÉaàa1\"]\n        \n        testStringParserSuccess(letters, inputs: matching) { input, result in\n            \n            let sameCount = result.count == countNumber\n            let joinedResult = result.joined(separator: \"\")\n            \n            let isMatch = sameCount && input.hasPrefix(joinedResult)\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let asdf = StringParser.string(\"asdf\").count(countNumber)\n        let matchingAsdf = [\"asdfasdfasdf\"]\n        \n        testStringParserSuccess(asdf, inputs: matchingAsdf) { input, result in\n            \n            let sameCount = result.count == countNumber\n            let joinedResult = result.joined(separator: \"\")\n            \n            let isMatch = sameCount && input.hasPrefix(joinedResult)\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatchingAsdf = [\"asd1\", \"asdfasdfasd1\", \"1asdf\", \"asdf\"]\n        let shouldFailMessage = \"GenericParser.count should fail.\"\n        \n        testStringParserFailure(asdf, inputs: notMatchingAsdf)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testChainRight() {\n        \n        let digits = StringParser.digit.many1.stringValue\n        let dot = StringParser.character(\".\").stringValue\n        let decimal = GenericParser.lift2(+, parser1: dot, parser2: digits)\n        let double = GenericParser.lift2(\n            +,\n            parser1: digits,\n            parser2: decimal\n        ).map { Double($0)! }\n        \n        let power: (Double, Double) -> Double = pow\n        let expOp = StringParser.string(\"**\") *> GenericParser(result: power)\n        let exp = double.chainRight(expOp, otherwise: 0)\n        \n        // Test for success.\n        let matching = [\n            \"2.0**2.0\", \"2.0**2.0aadsf\", \"2.0**3.0**3.0\", \"1.0\", \"a\"\n        ]\n        let expectedResult = [\n            power(2, 2), power(2.0, 2.0), power(2.0, power(3.0, 3.0)), 1.0, 0\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericParser.chainRight should succeed.\"\n        \n        testStringParserSuccess(exp, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expectedResult[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"2.0**\", \"2.0**2.0*\"]\n        let shouldFailMessage = \"GenericParser.chainRight should fail.\"\n        \n        testStringParserFailure(exp, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testChainRight1() {\n        \n        let digits = StringParser.digit.many1.stringValue\n        let dot = StringParser.character(\".\").stringValue\n        let decimal = GenericParser.lift2(+, parser1: dot, parser2: digits)\n        let double = GenericParser.lift2(\n            +,\n            parser1: digits,\n            parser2: decimal\n        ).map { Double($0)! }\n        \n        let power: (Double, Double) -> Double = pow\n        let expOp = StringParser.string(\"**\") *> GenericParser(result: power)\n        let exp = double.chainRight1(expOp)\n        \n        // Test for success.\n        let matching = [\"2.0**2.0\", \"2.0**2.0aadsf\", \"2.0**3.0**3.0\", \"1.0\"]\n        let expectedResult = [\n            power(2, 2), power(2.0, 2.0), power(2.0, power(3.0, 3.0)), 1.0\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericParser.chainRight1 should succeed.\"\n        \n        testStringParserSuccess(exp, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expectedResult[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"2.0**\", \"2.0**2.0*\", \"a\"]\n        let shouldFailMessage = \"GenericParser.chainRight1 should fail.\"\n        \n        testStringParserFailure(exp, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testChainLeft() {\n        \n        let addOp: GenericParser<String, (), (Int, Int) -> Int> =\n        StringParser.character(\"+\") *> GenericParser(result: +) <|>\n            StringParser.character(\"-\") *> GenericParser(result: -)\n        \n        let integer = StringParser.digit.many1.stringValue.map { Int($0)! }\n        \n        let add = integer.chainLeft(addOp, otherwise: 0)\n        \n        // Test for success.\n        let matchingAdd = [\"1+2+3\", \"1-2-3\", \"1\", \"a\"]\n        let expectedResultAdd = [1 + 2 + 3, 1 - 2 - 3, 1, 0]\n        \n        var index = 0\n        \n        let errorMessage = \"GenericParser.chainLeft should succeed.\"\n        \n        testStringParserSuccess(add, inputs: matchingAdd) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expectedResultAdd[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let mulOp: GenericParser<String, (), (Int, Int) -> Int> =\n        StringParser.character(\"*\") *> GenericParser(result: *) <|>\n            StringParser.character(\"/\") *> GenericParser(result: /)\n        \n        let mul = integer.chainLeft(mulOp, otherwise: 0)\n        \n        let matchingMul = [\"1*2*3\", \"16/2/4\", \"1\", \"a\"]\n        let expectedResultMul = [1 * 2 * 3, 16 / 2 / 4, 1, 0]\n        \n        index = 0\n        \n        testStringParserSuccess(mul, inputs: matchingMul) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expectedResultMul[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"2*\", \"2*2*\"]\n        let shouldFailMessage = \"GenericParser.chainLeft should fail.\"\n        \n        testStringParserFailure(mul, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testChainLeft1() {\n        \n        let addOp: GenericParser<String, (), (Int, Int) -> Int> =\n        StringParser.character(\"+\") *> GenericParser(result: +) <|>\n            StringParser.character(\"-\") *> GenericParser(result: -)\n        \n        let integer = StringParser.digit.many1.stringValue.map { Int($0)! }\n        \n        let add = integer.chainLeft1(addOp)\n        \n        // Test for success.\n        let matchingAdd = [\"1+2+3\", \"1-2-3\", \"1\"]\n        let expectedResultAdd = [1 + 2 + 3, 1 - 2 - 3, 1]\n        \n        var index = 0\n        \n        let errorMessage = \"GenericParser.chainLeft1 should succeed.\"\n        \n        testStringParserSuccess(add, inputs: matchingAdd) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expectedResultAdd[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let mulOp: GenericParser<String, (), (Int, Int) -> Int> =\n        StringParser.character(\"*\") *> GenericParser(result: *) <|>\n            StringParser.character(\"/\") *> GenericParser(result: /)\n        \n        let mul = integer.chainLeft1(mulOp)\n        \n        let matchingMul = [\"1*2*3\", \"16/2/4\", \"1\"]\n        let expectedResultMul = [1 * 2 * 3, 16 / 2 / 4, 1]\n        \n        index = 0\n        \n        testStringParserSuccess(mul, inputs: matchingMul) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expectedResultMul[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"2*\", \"2*2*\", \"a\"]\n        let shouldFailMessage = \"GenericParser.chainLeft1 should fail.\"\n        \n        testStringParserFailure(mulOp, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testNoOccurence() {\n        \n        let alphaNum = StringParser.alphaNumeric\n        let keyworkLet = StringParser.string(\"let\") <* alphaNum.noOccurence\n        \n        // Test for success.\n        let matching = [\"let\", \"let;\", \"let \"]\n        \n        let errorMessage = \"GenericParser.noOccurence should succeed.\"\n        \n        testStringParserSuccess(keyworkLet, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(result)\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"lets\", \"let2\", \"le\", \"a\"]\n        let shouldFailMessage = \"GenericParser.noOccurence should fail.\"\n        \n        testStringParserFailure(keyworkLet, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testManyTill() {\n        \n        let commentStartStr = \"<!--\"\n        \n        let anyChar = StringParser.anyCharacter\n        let commentStart = StringParser.string(commentStartStr)\n        let commentEnd = StringParser.string(\"-->\")\n        let comment = (\n            commentStart *> anyChar.manyTill(commentEnd.attempt)\n        ).stringValue\n        \n        // Test for success.\n        let matching = [\n            \"<!-- A comment -->\", \"<!-- Un autre en français -->\", \"<!---->\"\n        ]\n        \n        let errorMessage = \"GenericParser.manyTill should succeed.\"\n        \n        testStringParserSuccess(comment, inputs: matching) { inputStr, result in\n            \n            let startIndex = inputStr.startIndex\n            \n            var input = inputStr\n            input.removeSubrange(startIndex..<commentStartStr.endIndex)\n            \n            let isMatch = result.isEmpty || input.hasPrefix(result)\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: inputStr,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"<!-- A comment ->\", \"<!-- Un autre en français\", \"<---->\", \"a\"\n        ]\n        let shouldFailMessage = \"GenericParser.manyTill should fail.\"\n        \n        testStringParserFailure(comment, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testRecursive() {\n        \n        let openingParen = StringParser.character(\"(\")\n        let closingParen = StringParser.character(\")\")\n        \n        let decimal = GenericTokenParser<()>.decimal\n        \n        let operators: GenericParser<String, (), (Int, Int) -> Int> =\n        StringParser.character(\"+\") *> GenericParser(result: +) <|>\n            StringParser.character(\"-\") *> GenericParser(result: -)\n        \n        let expression = GenericParser<String, (), Int>.recursive\n        { expression in\n            \n            func opParser(_ left: Int) -> GenericParser<String, (), Int> {\n                \n                return operators >>- { f in\n                    \n                    expression >>- { right in\n                        \n                        opParser1(f(left, right))\n                        \n                    }\n                    \n                }\n                \n            }\n            \n            func opParser1(_ right: Int) -> GenericParser<String, (), Int> {\n                \n                return opParser(right) <|> GenericParser(result: right)\n                \n            }\n            \n            return expression.between(\n                openingParen,\n                closingParen\n            ) <|> decimal >>- { term in\n                \n                opParser(term) <|> GenericParser(result: term)\n                \n            }\n            \n        }\n        \n        let matching = [\"3-(1+2)\", \"3-(1-(3+1))\"]\n        let expected = [3-(1+2), 3-(1-(3+1))]\n        \n        var index = 0\n        \n        let errorMessage = \"GenericParser.recursive did not succeed.\"\n        \n        testStringParserSuccess(expression, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testEof() {\n        \n        let eof = StringParser.eof\n        \n        // Test for success.\n        let matching = [\"\"]\n        \n        testStringParserSuccess(eof, inputs: matching) { _, _ in }\n        \n        // Test when not matching.\n        let notMatching = [\"\\n\", \"\\r\", \"\\n\\r\", \"a\"]\n        let shouldFailMessage = \"GenericParser.eof should fail.\"\n        \n        testStringParserFailure(eof, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n}\n\nextension CombinatorParsersTests {\n    static var allTests:\n    [(String, (CombinatorParsersTests) -> () throws -> Void)] {\n        return [\n            (\"testChoice\", testChoice),\n            (\"testOtherwise\", testOtherwise),\n            (\"testOptional\", testOptional),\n            (\"testDiscard\", testDiscard),\n            (\"testBetween\", testBetween),\n            (\"testSkipMany1\", testSkipMany1),\n            (\"testMany1\", testMany1),\n            (\"testSeparatedBy\", testSeparatedBy),\n            (\"testSeparatedBy1\", testSeparatedBy1),\n            (\"testDividedBy\", testDividedBy),\n            (\"testDividedBy1\", testDividedBy1),\n            (\"testCount\", testCount),\n            (\"testChainRight\", testChainRight),\n            (\"testChainRight1\", testChainRight1),\n            (\"testChainLeft\", testChainLeft),\n            (\"testChainLeft1\", testChainLeft1),\n            (\"testNoOccurence\", testNoOccurence),\n            (\"testManyTill\", testManyTill),\n            (\"testRecursive\", testRecursive),\n            (\"testEof\", testEof)\n        ]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/ErrorMessageTest.swift",
    "content": "//==============================================================================\n// ErrorMessageTest.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-28.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nclass ErrorMessageTests: XCTestCase {\n    \n    func testCharacterError() {\n        \n        let vowel = StringParser.oneOf(\"aeiou\")\n        let expectedVowel = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected \\\"z\\\"\"\n        \n        errorMessageTest(vowel, input: \"z\") { actual in\n            \n            XCTAssertEqual(\n                expectedVowel,\n                actual,\n                self.formatErrorMessage(\n                    expected: expectedVowel,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n        let char = StringParser.character(\"a\")\n        let expectedChar = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected \\\"z\\\"\\n\" +\n        \"expecting \\\"a\\\"\"\n        \n        errorMessageTest(char, input: \"z\") { actual in\n            \n            XCTAssertEqual(\n                expectedChar,\n                actual,\n                self.formatErrorMessage(\n                    expected: expectedChar,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testStringError() {\n        \n        let allo = StringParser.string(\"allo\")\n        let expected = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected \\\"z\\\"\\n\" +\n        \"expecting \\\"allo\\\"\"\n        \n        errorMessageTest(allo, input: \"allz\") { actual in\n            \n            XCTAssertEqual(\n                expected,\n                actual,\n                self.formatErrorMessage(\n                    expected: expected,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testEofError() {\n        \n        let allo = StringParser.string(\"allo\")\n        let expected = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected end of input\\n\" +\n        \"expecting \\\"allo\\\"\"\n        \n        errorMessageTest(allo, input: \"all\") { actual in\n            \n            XCTAssertEqual(\n                expected,\n                actual,\n                self.formatErrorMessage(\n                    expected: expected,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testChoiceError() {\n        \n        let allo = StringParser.string(\"allo\")\n        let hello = StringParser.string(\"hello\")\n        let hola = StringParser.string(\"hola\")\n        \n        let hellos = allo <|> hello <|> hola\n        \n        let expectedHellos = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected \\\"z\\\"\\n\" +\n        \"expecting \\\"allo\\\", \\\"hello\\\" or \\\"hola\\\"\"\n        \n        errorMessageTest(hellos, input: \"z\") { actual in\n            \n            XCTAssertEqual(\n                expectedHellos,\n                actual,\n                self.formatErrorMessage(\n                    expected: expectedHellos,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n        let expectedEOF = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected end of input\\n\" +\n        \"expecting \\\"allo\\\"\"\n        \n        errorMessageTest(hellos, input: \"all\") { actual in\n            \n            XCTAssertEqual(\n                expectedEOF,\n                actual,\n                self.formatErrorMessage(\n                    expected: expectedEOF,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testCtrlCharError() {\n        \n        let allo = StringParser.string(\"\\tallo\\n\\r\")\n        let expected = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected \\\"a\\\"\\n\" +\n        \"expecting \\\"\\\\tallo\\\\n\\\\r\\\"\"\n        \n        errorMessageTest(allo, input: \"all\") { actual in\n            \n            XCTAssertEqual(\n                expected,\n                actual,\n                self.formatErrorMessage(\n                    expected: expected,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testPositionError() {\n        \n        let spaces = StringParser.spaces\n        let allo = StringParser.string(\"allo\")\n        \n        let parser = spaces *> allo\n        \n        let expectedTab = \"\\\"test\\\" (line 1, column 9):\\n\" +\n        \"unexpected end of input\\n\" +\n        \"expecting \\\"allo\\\"\"\n        \n        errorMessageTest(parser, input: \"\\tall\") { actual in\n            \n            XCTAssertEqual(\n                expectedTab,\n                actual,\n                self.formatErrorMessage(\n                    expected: expectedTab,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n        let expectedSpaces = \"\\\"test\\\" (line 1, column 5):\\n\" +\n        \"unexpected end of input\\n\" +\n        \"expecting \\\"allo\\\"\"\n        \n        errorMessageTest(parser, input: \"    all\") { actual in\n            \n            XCTAssertEqual(\n                expectedSpaces,\n                actual,\n                self.formatErrorMessage(\n                    expected: expectedSpaces,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n        let expectedLine = \"\\\"test\\\" (line 3, column 1):\\n\" +\n        \"unexpected end of input\\n\" +\n        \"expecting \\\"allo\\\"\"\n        \n        errorMessageTest(parser, input: \"\\n\\nall\") { actual in\n            \n            XCTAssertEqual(\n                expectedLine,\n                actual,\n                self.formatErrorMessage(\n                    expected: expectedLine,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testNoOccurenceError() {\n        \n        let spaces = StringParser.spaces\n        let allo = StringParser.string(\"allo\")\n        let parser = spaces *> allo.noOccurence\n        \n        let expected = \"\\\"test\\\" (line 3, column 5):\\n\" +\n        \"unexpected \\\"allo\\\"\"\n        \n        errorMessageTest(parser, input: \"\\n\\nallo\") { actual in\n            \n            XCTAssertEqual(\n                expected,\n                actual,\n                self.formatErrorMessage(\n                    expected: expected,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testLabelError() {\n        \n        let newline = StringParser.newLine\n        let expected = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected \\\"z\\\"\\n\" +\n        \"expecting lf new-line\"\n        \n        errorMessageTest(newline, input: \"z\") { actual in\n            \n            XCTAssertEqual(\n                expected,\n                actual,\n                self.formatErrorMessage(\n                    expected: expected,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testMultiLabelError() {\n        \n        let newline = StringParser.newLine.labels(\"a\", \"b\", \"c\")\n        let expected = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected \\\"z\\\"\\n\" +\n        \"expecting a, b or c\"\n        \n        errorMessageTest(newline, input: \"z\") { actual in\n            \n            XCTAssertEqual(\n                expected,\n                actual,\n                self.formatErrorMessage(\n                    expected: expected,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n        let charA = StringParser.character(\"a\").labels()\n        let emptyExpected = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unexpected \\\"z\\\"\"\n        \n        errorMessageTest(charA, input: \"z\") { actual in\n            \n            XCTAssert(\n                emptyExpected == actual,\n                self.formatErrorMessage(\n                    expected: expected,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testGenericError() {\n        \n        let fail = StringParser.fail(\"I always fail\")\n        let expected = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"I always fail\"\n        \n        errorMessageTest(fail, input: \"\") { actual in\n            \n            XCTAssertEqual(\n                expected,\n                actual,\n                self.formatErrorMessage(\n                    expected: expected,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n\n    func testUnknownError() {\n        \n        let empty = StringParser.empty\n        let expected = \"\\\"test\\\" (line 1, column 1):\\n\" +\n        \"unknown parse error\"\n        \n        errorMessageTest(empty, input: \"z\") { actual in\n            \n            XCTAssertEqual(\n                expected,\n                actual,\n                self.formatErrorMessage(\n                    expected: expected,\n                    actual: actual\n                )\n            )\n            \n        }\n        \n    }\n    \n    func errorMessageTest<Result>(\n        _ parser: GenericParser<String, (), Result>,\n        input: String,\n        assert: (String) -> Void\n    ) {\n        \n        do {\n            \n            try _ = parser.run(sourceName: \"test\", input: input)\n            \n        } catch let error {\n            \n            let errorStr = String(describing: error)\n            assert(errorStr)\n            \n        }\n        \n    }\n    \n    func formatErrorMessage(expected: String, actual: String) -> String {\n        \n        return \"Error messages error, \" +\n            \"Expected:\\n\\(expected)\\nActual:\\n\\(actual)\"\n        \n    }\n    \n}\n\nextension ErrorMessageTests {\n    static var allTests: [(String, (ErrorMessageTests) -> () throws -> Void)] {\n        return [\n            (\"testCharacterError\", testCharacterError),\n            (\"testStringError\", testStringError),\n            (\"testEofError\", testEofError),\n            (\"testChoiceError\", testChoiceError),\n            (\"testCtrlCharError\", testCtrlCharError),\n            (\"testPositionError\", testPositionError),\n            (\"testNoOccurenceError\", testNoOccurenceError),\n            (\"testLabelError\", testLabelError),\n            (\"testMultiLabelError\", testMultiLabelError),\n            (\"testGenericError\", testGenericError),\n            (\"testUnknownError\", testUnknownError)\n        ]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/ExpressionParserTests.swift",
    "content": "//==============================================================================\n// ExpressionParserTests.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-30.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\nimport func Foundation.pow\n@testable import SwiftParsec\n\nclass ExpressionParserTests: XCTestCase {\n    \n    func testExpr() {\n        \n        let power: (Int, Int) -> Int = { base, exp in\n            \n            Int(pow(Double(base), Double(exp)))\n        \n        }\n        \n        let opTable: OperatorTable<String, (), Int> = [\n            \n            [\n                prefix(\"-\", function: -),\n                prefix(\"+\", function: { $0 })\n            ],\n            [\n                postfix(\"²\", function: { $0 * $0 })\n            ],\n            [\n                binary(\">>\", function: >>, assoc: .none),\n                binary(\"<<\", function: <<, assoc: .none)\n            ],\n            [\n                binary(\"^\", function: power, assoc: .right)\n            ],\n            [\n                binary(\"*\", function: *, assoc: .left),\n                binary(\"/\", function: /, assoc: .left)\n            ],\n            [\n                binary(\"+\", function: +, assoc: .left),\n                binary(\"-\", function: -, assoc: .left)\n            ]\n        \n        ]\n        \n        let openingParen = StringParser.character(\"(\")\n        let closingParen = StringParser.character(\")\")\n        let decimal = GenericTokenParser<()>.decimal\n        \n        let expr = opTable.makeExpressionParser { expr in\n            \n            expr.between(openingParen, closingParen) <|> decimal\n            \n        }\n        \n        let matching = [\n            \"1+2*4-8+((3-12)/8)+(-71)+2^2^3\", \"(+3-3)+5\", \"3²\", \"4>>2\", \"4<<2\"\n        ]\n        \n        var expected = [1+2*4-8+((3-12)/8)+(-71)+power(2, power(2, 3))]\n        expected.append((+3-3)+5)\n        expected.append(3*3)\n        expected.append(4>>2)\n        expected.append(4<<2)\n        \n        var index = 0\n        \n        let errorMessage = \"OperatorTable.expressionParser should succeed.\"\n        \n        testStringParserSuccess(expr, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testReplaceRange() {\n        \n        var opTable = OperatorTable<String, (), Int>()\n        \n        opTable.append([\n            prefix(\"-\", function: -),\n            prefix(\"+\", function: { $0 })\n        ])\n        \n        opTable.append([\n            binary(\"*\", function: *, assoc: .left),\n            binary(\"/\", function: /, assoc: .left)\n        ])\n        \n        XCTAssertEqual(opTable.count, 2)\n        \n        opTable.replaceSubrange(0..<1, with: [])\n        \n        XCTAssertEqual(opTable.count, 1)\n        \n    }\n    \n    func binary(\n        _ name: String,\n        function: @escaping (Int, Int) -> Int,\n        assoc: Associativity\n    ) -> Operator<String, (), Int> {\n        \n        let opParser = StringParser.string(name) *>\n            GenericParser(result: function)\n        return .infix(opParser, assoc)\n        \n    }\n    \n    func prefix(\n        _ name: String,\n        function: @escaping (Int) -> Int\n    ) -> Operator<String, (), Int> {\n        \n        let opParser = StringParser.string(name) *>\n            GenericParser(result: function)\n        return .prefix(opParser)\n        \n    }\n    \n    func postfix(\n        _ name: String,\n        function: @escaping (Int) -> Int\n    ) -> Operator<String, (), Int> {\n        \n        let opParser = StringParser.string(name) *>\n            GenericParser(result: function)\n        return .postfix(opParser.attempt)\n        \n    }\n    \n}\n\nextension ExpressionParserTests {\n    static var allTests:\n    [(String, (ExpressionParserTests) -> () throws -> Void)] {\n        return [\n            (\"testExpr\", testExpr),\n            (\"testReplaceRange\", testReplaceRange)\n        ]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/GenericParserTests.swift",
    "content": "//==============================================================================\n// GenericParserTests.swift\n// SwiftParsecTests\n//\n// Created by David Dufresne on 2015-09-04.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nclass GenericParserTests: XCTestCase {\n    \n    func testMap() {\n        \n        let trans = { (num: Int) in String(num) }\n        let int99 = 99\n        \n        let intParser = GenericParser<String, (), Int>(result: int99)\n        let mappedParser = trans <^> intParser\n        \n        let errorMessage = \"GenericParser.map should succeed.\"\n        \n        testParserSuccess(mappedParser) { input, result in\n            \n            XCTAssertEqual(\n                trans(99),\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let int1 = 1\n        \n        let functorParser = curriedPlus(int1) <^> intParser\n        \n        testParserSuccess(functorParser) { input, result in\n            \n            XCTAssertEqual(\n                int99 + int1,\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testApplicative() {\n        \n        let int99 = 99\n        let int99Parser = GenericParser<String, (), Int>(result: int99)\n        \n        let int1 = 1\n        let int1Parser = GenericParser<String, (), Int>(result: int1)\n        \n        let errorMessage = \"GenericParser.apply should succeed.\"\n        \n        let applyParser = curriedPlus <^> int99Parser <*> int1Parser\n        testParserSuccess(applyParser) { input, result in\n            \n            XCTAssertEqual(\n                int99 + int1,\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let rightParser = int99Parser *> int1Parser\n        testParserSuccess(rightParser) { input, result in\n            \n            XCTAssertEqual(\n                int1,\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let leftParser = int99Parser <* int1Parser\n        testParserSuccess(leftParser) { input, result in\n            \n            XCTAssertEqual(\n                int99,\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testAlternative() {\n        \n        let empty = StringParser.empty\n        let letter = StringParser.oneOf(\"abc\")\n        let alt1 = empty <|> letter\n        \n        let errorMessage = \"GenericParser.alternative should succeed.\"\n        \n        testStringParserSuccess(alt1, inputs: [\"adsf\"]) { input, result in\n            \n            let isMatch = input.hasPrefix(String(result))\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        let string1 = StringParser.string(\"xads\")\n        let string2 = StringParser.string(\"asdfg\")\n        let alt2 = string1 <|> string2\n        \n        let matching = [\"asdfg, asdfg123\"]\n        \n        testStringParserSuccess(alt2, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(result)\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testFlatMap() {\n        \n        let letterDigit = StringParser.oneOf(\"abc\") >>- { letter in\n            \n            StringParser.digit >>- { digit in\n                \n                return GenericParser(result: String(letter) + String(digit))\n                \n            }\n            \n        }\n        \n        let matching = [\"a1\", \"b0\", \"c9\"]\n        let errorMessage = \"GenericParser.flatMap should succeed.\"\n        \n        testStringParserSuccess(letterDigit, inputs: matching)\n        { input, result in\n            \n            XCTAssertEqual(\n                input,\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testAtempt() {\n        \n        let string1 = StringParser.string(\"asdx\")\n        let string2 = StringParser.string(\"asdfg\")\n        let attempt = string1.attempt <|> string2\n        \n        let matching = [\"asdfg\", \"asdfg123\"]\n        let errorMessage = \"GenericParser.attempt should succeed.\"\n        \n        testStringParserSuccess(attempt, inputs: matching) { input, result in\n            \n            let isMatch = input.hasPrefix(result)\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testLookAhead() {\n        \n        let longestMatch = \"asdfg\"\n        \n        let string1 = StringParser.string(\"asd\")\n        let string2 = StringParser.string(longestMatch)\n        let lookAhead = string1.lookAhead *> string2\n        \n        let matching = [longestMatch, longestMatch + \"123\"]\n        let errorMessage = \"GenericParser.lookAhead should succeed.\"\n        \n        testStringParserSuccess(lookAhead, inputs: matching) { input, result in\n            \n            XCTAssertEqual(\n                longestMatch,\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"sad\", \"das\", \"asdasdfg\"]\n        let shouldFailMessage = \"GenericParser.lookAhead should fail.\"\n        \n        testStringParserFailure(lookAhead, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testMany() {\n        \n        let manyString = StringParser.string(\"asdf\").many\n        let matching = [\"asdfasdf\", \"asdfasdfasdf\", \"asdfasdfasdfasdf\", \"xasdf\"]\n        let errorMessage = \"GenericParser.many should succeed.\"\n        \n        testStringParserSuccess(manyString, inputs: matching) { input, result in\n            \n            let isMatch = result.isEmpty ||\n                input == result.joined(separator: \"\")\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\"asd\", \"asdfasd\"]\n        let shouldFailMessage = \"GenericParser.many should fail.\"\n        \n        testStringParserFailure(manyString, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testSkipMany() {\n        \n        let skipManyString = StringParser.string(\"asdf\").skipMany\n        \n        let matching = [\"asdfasdf\", \"asdfasdfasdf\", \"asdfasdfasdfasdf\", \"xasdf\"]\n        testStringParserSuccess(skipManyString, inputs: matching) { _, _ in }\n        \n        // Test when not matching.\n        let notMatching = [\"asd\", \"asdfasd\"]\n        let shouldFailMessage = \"GenericParser.skipMany should fail.\"\n        \n        testStringParserFailure(skipManyString, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testEmpty() {\n        \n        let empty = StringParser.empty\n        \n        let shouldFailMessage = \"GenericParser.empty should fail.\"\n        \n        testStringParserFailure(empty, inputs: [\"\"]) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testLabel() {\n        \n        let labelStr = \"letter x\"\n        \n        let letterx = StringParser.character(\"x\") <?> labelStr\n        let letterXx = StringParser.character(\"x\") <|>\n            StringParser.character(\"X\") <?> labelStr\n        let input = \"a\"\n        \n        for parser in [letterx, letterXx] {\n            \n            do {\n                \n                try _ = parser.run(sourceName: \"\", input: input)\n                XCTFail(\"GenericParser.label should fail.\")\n                \n            } catch let parseError as ParseError {\n                \n                var containsExpected = false\n                var containsSystemUnexpected = false\n                \n                for msg in parseError.messages {\n                    \n                    switch msg {\n                        \n                    case .expected(let str) where str == labelStr:\n                        \n                        containsExpected = true\n                        \n                    case .systemUnexpected(let str)\n                    where str == String(reflecting: input):\n                        \n                        containsSystemUnexpected = true\n                        \n                    default: continue\n                        \n                    }\n                    \n                }\n                \n                if !containsExpected || !containsSystemUnexpected {\n                    \n                    XCTFail(\"GenericParser.label should succeed.\")\n                    \n                }\n                \n            } catch let error {\n                \n                XCTFail(String(describing: error))\n                \n            }\n            \n        }\n        \n    }\n    \n    func testLift2() {\n        \n        let leftNumber = 1\n        let rightNumber = 2\n        \n        let left = GenericParser<String, (), Int>(result: leftNumber)\n        let right = GenericParser<String, (), Int>(result: rightNumber)\n        \n        let add = GenericParser.lift2(-, parser1: left, parser2: right)\n        \n        let errorMessage = \"GenericParser.lift2 should succeed.\"\n        testParserSuccess(add) { input, result in\n            \n            let isMatch = result == leftNumber - rightNumber\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testLift3() {\n        \n        let number1 = 1\n        let number2 = 2\n        let number3 = 3\n        \n        let num1 = GenericParser<String, (), Int>(result: number1)\n        let num2 = GenericParser<String, (), Int>(result: number2)\n        let num3 = GenericParser<String, (), Int>(result: number3)\n        \n        let add = GenericParser.lift3(\n            { $0 - $1 - $2 },\n            parser1: num1,\n            parser2: num2,\n            parser3: num3\n        )\n        \n        let errorMessage = \"GenericParser.lift3 should succeed.\"\n        testParserSuccess(add) { input, result in\n            \n            let isMatch = result == number1 - number2 - number3\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testLift4() {\n        \n        let number1 = 1\n        let number2 = 2\n        let number3 = 3\n        let number4 = 4\n        \n        let num1 = GenericParser<String, (), Int>(result: number1)\n        let num2 = GenericParser<String, (), Int>(result: number2)\n        let num3 = GenericParser<String, (), Int>(result: number3)\n        let num4 = GenericParser<String, (), Int>(result: number4)\n        \n        let add = GenericParser.lift4(\n            { $0 - $1 - $2 - $3 },\n            parser1: num1,\n            parser2: num2,\n            parser3: num3,\n            parser4: num4\n        )\n        \n        let errorMessage = \"GenericParser.lift4 should succeed.\"\n        testParserSuccess(add) { input, result in\n            \n            let isMatch = result == number1 - number2 - number3 - number4\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testLift5() {\n        \n        let number1 = 1\n        let number2 = 2\n        let number3 = 3\n        let number4 = 4\n        let number5 = 5\n        \n        let num1 = GenericParser<String, (), Int>(result: number1)\n        let num2 = GenericParser<String, (), Int>(result: number2)\n        let num3 = GenericParser<String, (), Int>(result: number3)\n        let num4 = GenericParser<String, (), Int>(result: number4)\n        let num5 = GenericParser<String, (), Int>(result: number5)\n        \n        let add = GenericParser.lift5(\n            { $0 - $1 - $2 - $3 - $4 },\n            parser1: num1,\n            parser2: num2,\n            parser3: num3,\n            parser4: num4,\n            parser5: num5\n        )\n        \n        let errorMessage = \"GenericParser.lift4 should succeed.\"\n        testParserSuccess(add) { input, result in\n            \n            let isMatch =\n                result == number1 - number2 - number3 - number4 - number5\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testUpdateUserState() {\n        \n        let updateUserState =\n        GenericParser<String, Int, Character>.updateUserState(curriedPlus(1))\n        \n        let countLetters =\n            GenericParser<String, Int, Character>.letter <* updateUserState\n        let digits = GenericParser<String, Int, Character>.digit\n        let alphaNum = countLetters <* digits.skipMany\n        \n        let matching = [\"a1234H23A3A0à1234É5678ê0ç6ë7\"]\n        \n        let errorMessage = \"GenericParser.updateUserState should succeed.\"\n        \n        let userState = alphaNum.many *>\n            GenericParser<String, Int, Int>.userState\n        do {\n            \n            for input in matching {\n                \n                let state = try userState.run(\n                    userState: 0,\n                    sourceName: \"\",\n                    input: input\n                )\n                \n                let alphaCharacters = input.filter { $0.isAlpha }\n                if state != alphaCharacters.count {\n                    \n                    XCTFail(errorMessage)\n                \n                }\n                \n            }\n            \n        } catch let parseError as ParseError {\n            \n            XCTFail(String(describing: parseError))\n            \n        } catch let error {\n            \n            XCTFail(String(describing: error))\n            \n        }\n        \n    }\n    \n    func testParseArray() {\n        \n        let charArray: [Character] = [\"h\", \"e\", \"l\", \"l\", \"o\"]\n        let parser = GenericParser<[Character], (), [Character]>.string(\n            charArray\n        )\n        \n        do {\n            \n            let result = try parser.run(sourceName: \"\", input: charArray)\n            XCTAssert(result == charArray, \"Array parse should succeed.\")\n            \n        } catch let parseError as ParseError {\n            \n            XCTFail(String(describing: parseError))\n            \n        } catch let error {\n            \n            XCTFail(String(describing: error))\n            \n        }\n        \n    }\n    \n}\n\n/// Types implementing the `PlusOperator` protocol have to have an\n/// implementation for the `+` operator.\nprotocol PlusOperator {\n    \n    static func +(lhs: Self, rhs: Self) -> Self\n    \n}\n\nextension Int: PlusOperator {}\nextension Double: PlusOperator {}\nextension String: PlusOperator {}\n\n/// Curried version of the `+` operator for `Int`.\nfunc curriedPlus<T: PlusOperator>(_ lhs: T) -> (T) -> T {\n    \n    return { rhs in lhs + rhs }\n    \n}\n\nextension GenericParserTests {\n    static var allTests: [(String, (GenericParserTests) -> () throws -> Void)] {\n        return [\n            (\"testMap\", testMap),\n            (\"testApplicative\", testApplicative),\n            (\"testAlternative\", testAlternative),\n            (\"testFlatMap\", testFlatMap),\n            (\"testAtempt\", testAtempt),\n            (\"testLookAhead\", testLookAhead),\n            (\"testMany\", testMany),\n            (\"testSkipMany\", testSkipMany),\n            (\"testEmpty\", testEmpty),\n            (\"testLabel\", testLabel),\n            (\"testLift2\", testLift2),\n            (\"testLift3\", testLift3),\n            (\"testLift4\", testLift4),\n            (\"testLift5\", testLift5),\n            (\"testUpdateUserState\", testUpdateUserState),\n            (\"testParseArray\", testParseArray)\n        ]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/GenericTokenParserTests.swift",
    "content": "//==============================================================================\n// DefaultTokenParserTests.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-10-14.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nclass GenericTokenParserTests: XCTestCase {\n    \n    func testIdentifier() {\n        //\n        // Case sensitive\n        //\n        do {\n            \n            let swift = LanguageDefinition<()>.swift\n            let swiftIdentifier =\n                GenericTokenParser(languageDefinition: swift).identifier\n            \n            let empty = LanguageDefinition<()>.empty\n            let identifier =\n                GenericTokenParser(languageDefinition: empty).identifier\n            \n            // Test for success.\n            let swiftMatching = [\n                \"test\", \"breakTest\", \"classTest\", \"t\", \"Break\", \"Class\", \"$0\",\n                \"$1\"\n            ]\n            let matching = [\n                \"test\", \"breakTest\", \"classTest\", \"t\", \"Break\", \"Class\"\n            ]\n            \n            let parsersAssociation = [\n                (swiftIdentifier, swiftMatching), (identifier, matching)\n            ]\n            \n            let errorMessage = \"GenericTokenParser.identifier should succeed.\"\n            \n            for (parser, inputs) in parsersAssociation {\n                \n                testStringParserSuccess(parser, inputs: inputs)\n                { input, result in\n                    \n                    XCTAssertEqual(\n                        input,\n                        result,\n                        self.formatErrorMessage(\n                            errorMessage,\n                            input: input,\n                            result: result\n                        )\n                    )\n                    \n                }\n                \n            }\n            \n            // Test when not matching.\n            let notMatching = swift.reservedNames\n            \n            let shouldFailMessage =\n                \"GenericTokenParser.identifier should fail.\"\n            \n            testStringParserFailure(swiftIdentifier, inputs: notMatching)\n            { input, result in\n                \n                XCTFail(\n                    self.formatErrorMessage(\n                        shouldFailMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n        //\n        // Not case sensitive\n        //\n        do {\n            \n            var swift = LanguageDefinition<()>.swift\n            swift.isCaseSensitive = false\n            \n            let identifier =\n                GenericTokenParser(languageDefinition: swift).identifier\n            \n            // Test for success.\n            let matching = [\n                \"test\", \"breakTest\", \"classTest\", \"BreakTest\", \"ClassTest\", \"t\"\n            ]\n            \n            let errorMessage =\n                \"GenericTokenParser.identifier should succeed.\"\n            \n            testStringParserSuccess(identifier, inputs: matching)\n            { input, result in\n                \n                XCTAssertEqual(\n                    input,\n                    result,\n                    self.formatErrorMessage(\n                        errorMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n            // Test when not matching.\n            let notMatchingLower = swift.reservedNames\n            let notMatching = notMatchingLower +\n                notMatchingLower.map { $0.uppercased() }\n            \n            let shouldFailMessage =\n                \"GenericTokenParser.identifier should fail.\"\n            \n            testStringParserFailure(identifier, inputs: notMatching)\n            { input, result in\n                \n                XCTFail(\n                    self.formatErrorMessage(\n                        shouldFailMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n    }\n    \n    func testReservedName() {\n        \n        var swift = LanguageDefinition<()>.swift\n        let reservedName =\n            GenericTokenParser(languageDefinition: swift).reservedName\n        \n        swift.isCaseSensitive = false\n        let reservedCaseInsensitive =\n            GenericTokenParser(languageDefinition: swift).reservedName\n        \n        // Test for success.\n        let matching = swift.reservedNames\n        let uppercaseMatching = swift.reservedNames.map { $0.uppercased() }\n        \n        let reservedNames = matching.map { reservedName($0) }\n        let reservedUppercaseNames =\n            uppercaseMatching.map { reservedCaseInsensitive($0) }\n        \n        let matchingAssociation = zip(reservedNames, matching)\n        let uppercaseMatchingAssociation =\n            zip(reservedUppercaseNames, uppercaseMatching)\n        \n        for assocArray in [matchingAssociation, uppercaseMatchingAssociation] {\n            \n            for (parser, input) in assocArray {\n                \n                testStringParserSuccess(parser, inputs: [input]) { _, _ in }\n                \n            }\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = matching.map { $0 + \"Test\" }\n        let notMatchingAssociation = zip(reservedNames, notMatching)\n        let shouldFailMessage =\n            \"GenericTokenParser.reservedName should fail.\"\n        \n        for (parser, noMatch) in notMatchingAssociation {\n            \n            testStringParserFailure(parser, inputs: [noMatch])\n            { input, result in\n                \n                XCTFail(\n                    self.formatErrorMessage(\n                        shouldFailMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n    }\n    \n    func testLegalOperator() {\n        \n        let swift = LanguageDefinition<()>.swift\n        let legalOperator =\n            GenericTokenParser(languageDefinition: swift).legalOperator\n        \n        // Test for success.\n        let matching = [\n            \"/>\", \"=>\", \"-<\", \"+\", \"!>\", \"*\", \"%>\", \"<>\", \"><\", \"&>\", \"|>\",\n            \"^>\", \"?>\", \"~>\"\n        ]\n        \n        let errorMessage = \"GenericTokenParser.legalOperator should succeed.\"\n        \n        testStringParserSuccess(legalOperator, inputs: matching)\n        {input, result in\n            \n            XCTAssertEqual(\n                input,\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = swift.reservedOperators\n        let shouldFailMessage =\n            \"GenericTokenParser.legalOperator should fail.\"\n        \n        testStringParserFailure(legalOperator, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testReservedOperator() {\n        \n        let swift = LanguageDefinition<()>.swift\n        let reservedOperator =\n            GenericTokenParser(languageDefinition: swift).reservedOperator\n        \n        // Test for success.\n        let matching = swift.reservedOperators\n        \n        let reservedOperators = matching.map { reservedOperator($0) }\n        let matchingAssociation = zip(reservedOperators, matching)\n        \n        for (parser, match) in matchingAssociation {\n            \n            testStringParserSuccess(parser, inputs: [match]) { _, _ in }\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = matching.map { $0 + \">\" }\n        let notMatchingAssociation = zip(reservedOperators, notMatching)\n        \n        let shouldFailMessage =\n            \"GenericTokenParser.reservedOperator should fail.\"\n        \n        for (parser, noMatch) in notMatchingAssociation {\n            \n            testStringParserFailure(parser, inputs: [noMatch])\n            { input, result in\n                \n                XCTFail(\n                    self.formatErrorMessage(\n                        shouldFailMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n    }\n    \n    func testCharacterLiteral() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let characterLiteral =\n            GenericTokenParser(languageDefinition: java).characterLiteral\n        \n        // Test for success.\n        let matching = [\n            \"'a'\", \"'\\\\97'\", \"'\\\\x61'\", \"'\\\\o141'\", \"'\\\\n'\", \"'\\\\CR'\", \"'\\\\^@'\",\n            \"'\\\\^A'\"\n        ]\n        let expected: [Character] = [\n            \"a\", \"a\", \"a\", \"a\", \"\\n\", \"\\r\", \"\\0\", \"\\u{0001}\"\n        ]\n        var index = 0\n        \n        let errorMessage =\n            \"GenericTokenParser.characterLiteral should succeed.\"\n        \n        testStringParserSuccess(characterLiteral, inputs: matching)\n        { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"'a\", \"'\\\\97\", \"'\\\\x61\", \"'\\\\o141\", \"'\\\\x'\", \"'\\\\ZZ'\", \"'\\\\^a'\",\n            \"'\\\\'\", \"'\\\\xFFFFFFFFFFFFFFF'\"\n        ]\n        \n        let shouldFailMessage =\n            \"GenericTokenParser.characterLiteral should fail.\"\n        \n        testStringParserFailure(characterLiteral, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testStringLiteral() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let stringLiteral =\n            GenericTokenParser(languageDefinition: java).stringLiteral\n        \n        // Test for success.\n        let matching = [\n            \"\\\"a\\\"\", \"\\\"\\\\97\\\"\", \"\\\"\\\\x61\\\"\", \"\\\"\\\\o141\\\"\", \"\\\"\\\\n\\\"\",\n            \"\\\"\\\\CR\\\"\", \"\\\"\\\\^@\\\"\", \"\\\"abc\\\\n\\\\x61\\\"\", \"\\\"\\\\130\\\\&11\\\"\",\n            \"\\\"foo\\\\&bar\\\"\",\n            \"\\\"this is a \\\\\\n\\\\long string,\\\\\\n\\\\ spanning multiple lines\\\"\"\n        ]\n        let expected = [\n            \"a\", \"a\", \"a\", \"a\", \"\\n\", \"\\r\", \"\\0\", \"abc\\na\", \"\\u{82}11\",\n            \"foobar\", \"this is a long string, spanning multiple lines\"\n        ]\n        var index = 0\n        \n        let errorMessage =\n            \"GenericTokenParser.stringLiteral should succeed.\"\n        \n        testStringParserSuccess(stringLiteral, inputs: matching)\n        { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"'a\", \"'\\\\97\", \"'\\\\x61\", \"'\\\\o141\", \"'\\\\x'\", \"'\\\\ZZ'\", \"'\\\\^a'\",\n            \"'\\\\'\"\n        ]\n        \n        let shouldFailMessage =\n            \"GenericTokenParser.stringLiteral should fail.\"\n        \n        testStringParserFailure(stringLiteral, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testSwiftStringLiteral() {\n        \n        let swift = LanguageDefinition<()>.swift\n        let stringLiteral =\n            GenericTokenParser(languageDefinition: swift).stringLiteral\n        \n        // Test for success.\n        let matching = [\n            \"\\\"a\\\"\", \"\\\"\\\\u{61}\\\"\", \"\\\"\\\\0\\\"\", \"\\\"\\\\\\\\\\\"\", \"\\\"\\\\t\\\"\", \"\\\"\\\\n\\\"\",\n            \"\\\"\\\\r\\\"\", \"\\\"\\\\\\\"\\\"\", \"\\\"\\\\\\'\\\"\", \"\\\"abc\\\\n\\\\u{61}\\\"\"\n        ]\n        let expected = [\n            \"a\", \"a\", \"\\0\", \"\\\\\", \"\\t\", \"\\n\", \"\\r\", \"\\\"\", \"\\'\", \"abc\\na\"\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.stringLiteral should succeed.\"\n        \n        testStringParserSuccess(stringLiteral, inputs: matching)\n        { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"\\\"a\", \"\\\"\\\\{61}\\\"\", \"\\\\0\\\"\", \"\\\"\\\\\\\"\", \"\\\"\\\\u{123456789}\\\"\",\n            \"\\\"\\\\u{FFFFFFFF}\\\"\"\n        ]\n        \n        let shouldFailMessage =\n            \"GenericTokenParser.stringLiteral should fail.\"\n        \n        testStringParserFailure(stringLiteral, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n\n    func testJSONStringLiteral() {\n        \n        let json = LanguageDefinition<()>.json\n        let stringLiteral =\n            GenericTokenParser(languageDefinition: json).stringLiteral\n        \n        // Test for success.\n        let matching = [\n            \"\\\"a\\\"\", \"\\\"\\\\u0061\\\"\", \"\\\"\\\\\\\"\\\"\", \"\\\"\\\\\\\\\\\"\", \"\\\"\\\\/\\\"\",\n            \"\\\"\\\\b\\\"\", \"\\\"\\\\f\\\"\", \"\\\"\\\\n\\\"\", \"\\\"\\\\r\\\"\", \"\\\"\\\\t\\\"\",\n            \"\\\"abc\\\\n\\\\u0061\\\"\", \"\\\"\\\\uD834\\\\uDD1E\\\"\"\n        ]\n        let expected = [\n            \"a\", \"a\", \"\\\"\", \"\\\\\", \"/\", \"\\u{0008}\", \"\\u{000C}\", \"\\n\", \"\\r\", \"\\t\",\n            \"abc\\na\", \"\\u{1D11E}\"\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.stringLiteral should succeed.\"\n        \n        testStringParserSuccess(stringLiteral, inputs: matching)\n        { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"\\\"a\", \"\\\"\\\\u061\\\"\", \"\\\"\\\\61\\\"\", \"\\\\0\\\"\", \"\\\"\\\\\\\"\", \"\\\"\\\\u\\\"\",\n            \"\\\"\\\\uD834\\\"\", \"\\\"\\\\uD834\\\\u0061\\\"\"\n        ]\n        \n        let shouldFailMessage =\n            \"GenericTokenParser.stringLiteral should fail.\"\n        \n        testStringParserFailure(stringLiteral, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testNatural() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let natural = GenericTokenParser(languageDefinition: java).natural\n        \n        // Test for success.\n        let matching = [\n            \"1\", \"1234\", \"0xf\", \"0xF\", \"0xffff\", \"0xFFFF\", \"0o1\", \"0o1234\", \"0\"]\n        \n        let expected = [1, 1234, 0xF, 0xF, 0xFFFF, 0xFFFF, 0o1, 0o1234, 0]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.natural should succeed.\"\n        \n        testStringParserSuccess(natural, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"-1\", \"-1234\", \"-0xf\", \"+0xF\", \"-0xffff\", \"+0xFFFF\", \"-0o1\",\n            \"-0o1234\"\n        ]\n        \n        let shouldFailMessage =\n            \"GenericTokenParser.natural should fail.\"\n        \n        testStringParserFailure(natural, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testInteger() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let integer = GenericTokenParser(languageDefinition: java).integer\n        \n        // Test for success.\n        let matching = [\n            \"1\", \"1234\", \"0xf\", \"0xF\", \"0xffff\", \"0xFFFF\", \"0o1\", \"0o1234\", \"0\",\n            \"-1\", \"-1234\", \"-0xf\", \"+0xF\", \"-0xffff\", \"+0xFFFF\", \"-0o1\",\n            \"-0o1234\", \"-0\"\n        ]\n        let expected = [\n            1, 1234, 0xF, 0xF, 0xffff, 0xFFFF, 0o1, 0o1234, 0, -1, -1234, -0xF,\n            0xF, -0xffff, 0xFFFF, -0o1, -0o1234, -0\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.integer should succeed.\"\n        \n        testStringParserSuccess(integer, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"xf\", \"xF\", \"ffff\", \"FFFF\", \"o1\", \"o1234\", \"-xf\", \"+xF\", \"-ffff\",\n            \"+FFFF\", \"-o1\", \"+o1234\"\n        ]\n        \n        let shouldFailMessage = \"GenericTokenParser.integer should fail.\"\n        \n        testStringParserFailure(integer, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testIntegerAsFloat() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let integer =\n            GenericTokenParser(languageDefinition: java).integerAsFloat\n        \n        // Test for success.\n        let matching = [\n            \"1\", \"1234\", \"0xf\", \"0xF\", \"0xffff\", \"0xFFFF\", \"0o1\", \"0o1234\", \"0\",\n            \"-1\", \"-1234\", \"-0xf\", \"+0xF\", \"-0xffff\", \"+0xFFFF\", \"-0o1\",\n            \"-0o1234\", \"-0\"\n        ]\n        let expected: [Double] = [\n            1, 1234, 0xF, 0xF, 0xffff, 0xFFFF, 0o1, 0o1234, 0, -1, -1234, -0xF,\n            0xF, -0xffff, 0xFFFF, -0o1, -0o1234, -0\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.integerAsFloat should succeed.\"\n        \n        testStringParserSuccess(integer, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"xf\", \"xF\", \"ffff\", \"FFFF\", \"o1\", \"o1234\", \"-xf\", \"+xF\", \"-ffff\",\n            \"+FFFF\", \"-o1\", \"+o1234\"\n        ]\n        \n        let shouldFailMessage =\n            \"GenericTokenParser.integerAsFloat should fail.\"\n        \n        testStringParserFailure(integer, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testFloat() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let float = GenericTokenParser(languageDefinition: java).float\n        \n        // Test for success.\n        let matching = [\n            \"1.0\", \"1234.0\", \"0.0\", \"-1.0\", \"-1234.0\", \"-0.0\", \"1234e5\",\n            \"1.234E5\", \"1.234e-5\", \"1234E-5\", \"-1234e5\", \"-1.234E5\",\n            \"-1.234e-5\", \"-1234e-5\"\n        ]\n        let expected: [Double] = [\n            1.0, 1234.0, 0.0, -1.0, -1234.0, -0.0, 1234e5, 1.234E5, 1.234e-5,\n            1234E-5, -1234e5, -1.234E5, -1.234e-5, -1234e-5\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.float should succeed.\"\n        \n        testStringParserSuccess(float, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"1\", \"1234\", \"0\", \"-1\", \"-1234\", \"-0\", \"xf\", \"xF\", \"ffff\", \"FFFF\",\n            \"o1\", \"o1234\", \"-xf\", \"+xF\", \"-ffff\", \"+FFFF\", \"-o1\", \"+o1234\"\n        ]\n        \n        let shouldFailMessage = \"GenericTokenParser.float should fail.\"\n        \n        testStringParserFailure(float, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testNumber() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let number = GenericTokenParser(languageDefinition: java).number\n        \n        // Test for success.\n        let matching = [\n            \"1\", \"1234\", \"0xf\", \"0xF\", \"0xffff\", \"0xFFFF\", \"0o1\", \"0o1234\", \"0\",\n            \"-1\", \"-1234\", \"-0xf\", \"+0xF\", \"-0xffff\", \"+0xFFFF\", \"-0o1\",\n            \"-0o1234\", \"-0\", \"1.0\", \"1234.0\", \"0.0\", \"-1.0\", \"-1234.0\", \"-0.0\",\n            \"1234e5\", \"1.234E5\", \"1.234e-5\", \"1234E-5\", \"-1234e5\", \"-1.234E5\",\n            \"-1.234e-5\", \"-1234e-5\"\n        ]\n        let expected: [Either<Int, Double>] = [\n            .left(1), .left(1234), .left(0xF), .left(0xF), .left(0xffff),\n            .left(0xFFFF), .left(0o1), .left(0o1234), .left(0), .left(-1),\n            .left(-1234), .left(-0xF), .left(0xF), .left(-0xffff),\n            .left(0xFFFF), .left(-0o1), .left(-0o1234), .left(-0), .right(1.0),\n            .right(1234.0), .right(0.0), .right(-1.0), .right(-1234.0),\n            .right(-0.0), .right(1234e5), .right(1.234E5), .right(1.234e-5),\n            .right(1234E-5), .right(-1234e5), .right(-1.234E5),\n            .right(-1.234e-5), .right(-1234e-5)\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.number should succeed.\"\n        \n        testStringParserSuccess(number, inputs: matching) { input, result in\n            \n            let expect = expected[index]\n            index += 1\n            \n            switch result {\n                \n            case .left(let intRes):\n                \n                if case .left(let val) = expect, intRes == val {\n                    \n                    return\n                    \n                }\n                \n            case .right(let doubleRes):\n                \n                if case .right(let val) = expect, doubleRes == val {\n                    \n                    return\n                    \n                }\n                \n            }\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"xf\", \"xF\", \"ffff\", \"FFFF\", \"o1\", \"o1234\", \"-xf\", \"+xF\", \"-ffff\",\n            \"+FFFF\", \"-o1\", \"+o1234\"\n        ]\n        let shouldFailMessage = \"GenericTokenParser.number should fail.\"\n        \n        testStringParserFailure(number, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testDecimal() {\n        \n        let decimal = GenericTokenParser<()>.decimal\n        \n        // Test for success.\n        let matching = [\"1\", \"1234\", \"001234\"]\n        let expected = [1, 1234, 001234]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.decimal should succeed.\"\n        \n        testStringParserSuccess(decimal, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"-1\", \"-1234\", \"-0xf\", \"+0xF\", \"-0xffff\", \"+0xFFFF\",\n            \"-0o1\", \"-0o1234\", \"99999999999999999999999999\"\n        ]\n        \n        let shouldFailMessage = \"GenericTokenParser.decimal should fail.\"\n        \n        testStringParserFailure(decimal, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testHexadecimal() {\n        \n        let hexadecimal = GenericTokenParser<()>.hexadecimal\n        \n        // Test for success.\n        let matching = [\n            \"x1f\", \"x2F\", \"x3ffff\", \"x4FFFF\", \"xABCDEF\", \"X12345\", \"X67890\"\n        ]\n        let expected = [\n            0x1f, 0x2F, 0x3ffff, 0x4FFFF, 0xABCDEF, 0x12345, 0x67890\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.hexadecimal should succeed.\"\n        \n        testStringParserSuccess(hexadecimal, inputs: matching)\n        { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"1\", \"1234\", \"001234\", \"-1\", \"-1234\", \"-0xf\", \"+0xF\", \"-0xffff\",\n            \"+0xFFFF\", \"-0o1\", \"-0o1234\", \"xFFFFFFFFFFFFFFFFFFFFFFFFFF\"\n        ]\n        let shouldFailMessage =\n            \"GenericTokenParser.hexadecimal should fail.\"\n        \n        testStringParserFailure(hexadecimal, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testOctal() {\n        \n        let octal = GenericTokenParser<()>.octal\n        \n        // Test for success.\n        let matching = [\"o1\", \"O1234\", \"o567\"]\n        let expected = [0o1, 0o1234, 0o567]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.octal should succeed.\"\n        \n        testStringParserSuccess(octal, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            XCTAssertEqual(\n                expected[index],\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"1\", \"1234\", \"001234\", \"-1\", \"-1234\", \"-0xf\", \"+0xF\", \"-0xffff\",\n            \"+0xFFFF\", \"-0o1\", \"-0o1234\",\n            \"o777777777777777777777777777777777777\"\n        ]\n        \n        let shouldFailMessage = \"GenericTokenParser.octal should fail.\"\n        \n        testStringParserFailure(octal, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testSymbol() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let symbol = GenericTokenParser(languageDefinition: java).symbol\n        \n        // Test for success.\n        let names = [\"if\", \"let\", \"var\", \"case\"]\n        let symbols = names.map { symbol($0) }\n        \n        let matching = [\"if\\n\\t\\r \", \"let/* adsfadsfadsfadsf // */\",\n                        \"var// adsfadsfadsf\",\n                        \"case\\u{000B}\\u{000C}/*/* adsf*/*/\"\n        ]\n        var index = 0\n        \n        let errorMessage = \"GenericTokenParser.symbol should succeed.\"\n        \n        for (parser, input) in zip(symbols, matching) {\n            \n            testStringParserSuccess(parser, inputs: [input]) { input, result in\n                \n                defer { index += 1 }\n                XCTAssertEqual(\n                    names[index],\n                    result,\n                    self.formatErrorMessage(\n                        errorMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n    }\n    \n    func testWhiteSpace() {\n        \n        let str = \"a\"\n        let strParser = StringParser.string(str)\n        \n        let empty = LanguageDefinition<()>.empty\n        let simpleWhiteSpace =\n            GenericTokenParser(languageDefinition: empty).whiteSpace\n        \n        let removeWhiteSpace = simpleWhiteSpace *> strParser\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let javaWhiteSpace =\n            GenericTokenParser(languageDefinition: java).whiteSpace\n        \n        let removeJavaWhiteSpace = javaWhiteSpace *> strParser\n        \n        // Test for success.\n        let matchingParsers = [removeWhiteSpace, removeJavaWhiteSpace]\n        let matching = [\n            [\n                \" \" + str, \"\\t\" + str, \"\\n\" + str, \"\\r\" + str, \"\\r\\n\" + str,\n                \"\\u{000B}\" + str, \"\\u{000C}\" + str\n            ],\n            [\n                \"/*\\nMulti line\\n*/\" + str, \"// One line\\n\" + str,\n                \"/*/* Nested */*/\" + str\n            ]\n        ]\n        \n        let errorMessage = \"GenericTokenParser.whiteSpace should succeed.\"\n        \n        for (parser, input) in zip(matchingParsers, matching) {\n            \n            testStringParserSuccess(parser, inputs: input) { input, result in\n                \n                XCTAssertEqual(\n                    str,\n                    result,\n                    self.formatErrorMessage(\n                        errorMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n        // Test when not matching.\n        var emptyCommentLine = LanguageDefinition<()>.empty\n        emptyCommentLine.commentStart = \"/*\"\n        emptyCommentLine.commentEnd   = \"*/\"\n        let emptyCommentLineWhiteSpace =\n            GenericTokenParser(languageDefinition: emptyCommentLine).whiteSpace\n        \n        let removeCommentLine = emptyCommentLineWhiteSpace *> strParser\n        \n        var emptyMultiLine = LanguageDefinition<()>.empty\n        emptyMultiLine.commentLine = \"//\"\n        let emptyMultiLineWhiteSpace =\n            GenericTokenParser(languageDefinition: emptyMultiLine).whiteSpace\n        \n        let removeMultiLine = emptyMultiLineWhiteSpace *> strParser\n        \n        var nonNested = LanguageDefinition<()>.javaStyle\n        nonNested.allowNestedComments = false\n        let nonNestedWhiteSpace =\n            GenericTokenParser(languageDefinition: nonNested).whiteSpace\n        \n        let removeNonNested = nonNestedWhiteSpace *> strParser\n        \n        let notMatchingParsers = [\n            removeWhiteSpace, removeJavaWhiteSpace, removeCommentLine,\n            removeMultiLine, removeNonNested\n        ]\n        let notMatching = [\n            [\n                \"/*\\nMulti line\\n*/\" + str,\n                \"// One line\\n\" + str, \"/*/* Nested */*/\" + str\n            ],\n            [\"/*/* adsf */\" + str],\n            [\"// Line comment\\n\" + str],\n            [\"/* Multi line */\" + str],\n            [\"/*/* Nested */*/\" + str]\n        ]\n        \n        let shouldFailMessage =\n            \"GenericTokenParser.whiteSpace should fail.\"\n        \n        for (parser, input) in zip(notMatchingParsers, notMatching) {\n            \n            testStringParserFailure(parser, inputs: input) { input, result in\n                \n                XCTFail(\n                    self.formatErrorMessage(\n                        shouldFailMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n    }\n    \n    func testParentheses() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        \n        testBracketsParser(\n            lexer.parentheses,\n            parserName: \"parentheses\",\n            opening: \"(\",\n            closing: \")\"\n        )\n        \n    }\n    \n    func testBraces() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        \n        testBracketsParser(\n            lexer.braces,\n            parserName: \"braces\",\n            opening: \"{\", closing: \"}\"\n        )\n        \n    }\n    \n    func testAngles() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        \n        testBracketsParser(\n            lexer.angles,\n            parserName: \"angles\",\n            opening: \"<\",\n            closing: \">\"\n        )\n        \n    }\n    \n    func testBrackets() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        \n        testBracketsParser(\n            lexer.brackets,\n            parserName: \"brackets\",\n            opening: \"[\",\n            closing: \"]\"\n        )\n        \n    }\n    \n    func testPunctuations() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        \n        let parsers = [lexer.semicolon, lexer.comma, lexer.colon, lexer.dot]\n        let matching = [\";\", \",\", \":\", \".\"]\n        let errorMessage = \"One of the punctuation parsers should succeed.\"\n        \n        for (parser, match) in zip(parsers, matching) {\n            \n            testStringParserSuccess(parser, inputs: [match]) { input, result in\n                \n                XCTAssertEqual(\n                    input,\n                    result,\n                    self.formatErrorMessage(\n                        errorMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n    }\n    \n    func testSemicolonSeparated() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        \n        testPunctuationSeparated(lexer.semicolonSeparated,\n            parserName: \"semicolonSeparated\",\n            punctuation: \";\",\n            allowZeroOccurence: true)\n        \n    }\n    \n    func testSemicolonSeparated1() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        \n        testPunctuationSeparated(lexer.semicolonSeparated1,\n            parserName: \"semicolonSeparated1\",\n            punctuation: \";\",\n            allowZeroOccurence: false)\n        \n    }\n    \n    func testCommaSeparated() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        \n        testPunctuationSeparated(lexer.commaSeparated,\n            parserName: \"commaSeparated\",\n            punctuation: \",\",\n            allowZeroOccurence: true)\n        \n    }\n    \n    func testCommaSeparated1() {\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        \n        testPunctuationSeparated(lexer.commaSeparated1,\n            parserName: \"commaSeparated1\",\n            punctuation: \",\",\n            allowZeroOccurence: false)\n        \n    }\n    \n    func testBracketsParser(\n        _ parser: (\n            GenericParser<String, (), String>\n        ) -> GenericParser<String, (), String>,\n        parserName: String,\n        opening: String,\n        closing: String\n    ) {\n        \n        let expected = \"abcd\"\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        let brackets = parser(lexer.symbol(expected))\n        \n        // Test for success.\n        let matching = [\n            opening + \"abcd\" + closing,\n            opening + \" \\n\\t\\rabcd /*  */ \" + closing\n        ]\n        \n        let errorMessage =\n            \"GenericTokenParser.\" + parserName + \" should succeed.\"\n        \n        testStringParserSuccess(brackets, inputs: matching) { input, result in\n            \n            XCTAssertEqual(\n                expected,\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        let notMatching = [\n            \"abcd\" + closing, opening + \"abcd\", \" \\n\\t\\rabcd /*  */ \" + closing,\n            opening + \" \\n\\t\\rabcd /*  */ \", opening + closing\n        ]\n        let shouldFailMessage =\n            \"GenericTokenParser.\" + parserName + \" should fail.\"\n        \n        testStringParserFailure(brackets, inputs: notMatching)\n        { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testPunctuationSeparated(\n        _ parser: (\n            GenericParser<String, (), String>\n        ) -> GenericParser<String, (), [String]>,\n        parserName: String, punctuation: String,\n        allowZeroOccurence: Bool\n    ) {\n        \n        let expected = \"abcd\"\n        \n        let java = LanguageDefinition<()>.javaStyle\n        let lexer = GenericTokenParser(languageDefinition: java)\n        let sepBy = parser(lexer.symbol(expected))\n        \n        // Test for success.\n        var matching = [\n            expected,\n            expected + punctuation + \"  \" + expected + \"  \" + punctuation +\n                \"\\n\\t\\r\" + expected + \" \" + punctuation + \" /* 11111 */\"\n                + expected\n        ]\n        \n        if allowZeroOccurence { matching.append(\"\") }\n        \n        let errorMessage =\n            \"GenericTokenParser.\" + parserName + \" should succeed.\"\n        \n        testStringParserSuccess(sepBy, inputs: matching) { input, result in\n            \n            let isMatch = result.reduce(true) { $0 ? $1 == expected : false }\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test when not matching.\n        var notMatching = [expected + punctuation]\n        if !allowZeroOccurence { notMatching.append(\"\") }\n        \n        let shouldFailMessage =\n            \"GenericTokenParser.\" + parserName + \" should fail.\"\n        \n        testStringParserFailure(sepBy, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n\n}\n\nextension GenericTokenParserTests {\n    static var allTests:\n    [(String, (GenericTokenParserTests) -> () throws -> Void)] {\n        return [\n            (\"testIdentifier\", testIdentifier),\n            (\"testReservedName\", testReservedName),\n            (\"testLegalOperator\", testLegalOperator),\n            (\"testReservedOperator\", testReservedOperator),\n            (\"testCharacterLiteral\", testCharacterLiteral),\n            (\"testStringLiteral\", testStringLiteral),\n            (\"testSwiftStringLiteral\", testSwiftStringLiteral),\n            (\"testJSONStringLiteral\", testJSONStringLiteral),\n            (\"testNatural\", testNatural),\n            (\"testInteger\", testInteger),\n            (\"testIntegerAsFloat\", testIntegerAsFloat),\n            (\"testFloat\", testFloat),\n            (\"testNumber\", testNumber),\n            (\"testDecimal\", testDecimal),\n            (\"testHexadecimal\", testHexadecimal),\n            (\"testOctal\", testOctal),\n            (\"testSymbol\", testSymbol),\n            (\"testWhiteSpace\", testWhiteSpace),\n            (\"testParentheses\", testParentheses),\n            (\"testBraces\", testBraces),\n            (\"testAngles\", testAngles),\n            (\"testBrackets\", testBrackets),\n            (\"testPunctuations\", testPunctuations),\n            (\"testSemicolonSeparated\", testSemicolonSeparated),\n            (\"testSemicolonSeparated1\", testSemicolonSeparated1),\n            (\"testCommaSeparated\", testCommaSeparated),\n            (\"testCommaSeparated1\", testCommaSeparated1)\n        ]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>en</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleSignature</key>\n\t<string>????</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Tests/SwiftParsecTests/JSONBenchmarkTests.swift",
    "content": "//==============================================================================\n// BenchmarkTests.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2016-07-16.\n// Copyright © 2016 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\nimport SwiftParsec\nimport class Foundation.Bundle\n\nclass JSONBenchmarkTests: XCTestCase {\n    \n    private typealias JSONStatistics = (\n        booleanCount: Int,\n        numberCount: Int,\n        stringCount: Int,\n        arrayCount: Int,\n        objectCount: Int,\n        nullCount: Int\n    )\n    \n    private typealias StatisticsParser =\n        GenericParser<String, JSONStatistics, ()>\n    \n    // Test the performance of a parser gathering basic statistics on a JSON\n    // file. The goal is to keep the building part as light as possible to\n    // test the parsing speed without too much influence from the building part.\n    func testJSONStatisticsParserPerformance() {\n        \n        let json = LanguageDefinition<JSONStatistics>.json\n        let lexer = GenericTokenParser(languageDefinition: json)\n        let symbol = lexer.symbol\n        \n        let jbool = (symbol(\"true\") <|> symbol(\"false\")) *>\n        StatisticsParser.updateUserState { statistics in\n                \n            var stats = statistics\n            stats.booleanCount += 1\n                \n            return stats\n            \n        }\n        \n        let stringLiteral = lexer.stringLiteral\n        \n        let jstring = stringLiteral *>\n        StatisticsParser.updateUserState { statistics in\n                \n            var stats = statistics\n            stats.stringCount += 1\n                \n            return stats\n            \n        }\n        \n        let jnumber = (lexer.float.attempt <|> lexer.integerAsFloat) *>\n        StatisticsParser.updateUserState { statistics in\n                \n            var stats = statistics\n            stats.numberCount += 1\n                \n            return stats\n            \n        }\n        \n        let jnull = symbol(\"null\") *>\n        StatisticsParser.updateUserState { statistics in\n            \n            var stats = statistics\n            stats.nullCount += 1\n            \n            return stats\n            \n        }\n        \n        var jarray: GenericParser<String, JSONStatistics, ()>!\n        var jobject: GenericParser<String, JSONStatistics, ()>!\n        \n        let _ = GenericParser.recursive { (\n            jvalue: GenericParser<String, JSONStatistics, ()>\n        ) in\n            \n            let jarrayValues = lexer.commaSeparated(jvalue)\n            jarray = lexer.brackets(jarrayValues) *>\n            StatisticsParser.updateUserState { statistics in\n                    \n                var stats = statistics\n                stats.arrayCount += 1\n                    \n                return stats\n                    \n            }\n            \n            let nameValue = stringLiteral >>- { name in\n                    \n                symbol(\":\") *> jvalue.map { value in (name, ()) }\n                    \n            }\n            \n            let dictionary: GenericParser<String, JSONStatistics, [String: ()]> =\n            (symbol(\",\") *> nameValue).manyAccumulator { assoc, dict in\n                    \n                return dict\n                    \n            }\n            \n            let jobjectDict = nameValue >>- { assoc in\n                    \n                dictionary >>- { dict in\n                        \n                    return GenericParser(result: ())\n                        \n                }\n                    \n            }\n            \n            let jobjectValues = jobjectDict <|> GenericParser(result: ())\n            jobject = lexer.braces(jobjectValues) *>\n            StatisticsParser.updateUserState { statistics in\n                    \n                var stats = statistics\n                stats.objectCount += 1\n                \n                return stats\n                    \n            }\n            \n            return jstring <|> jnumber <|> jbool <|> jnull <|> jarray <|>\n                jobject\n            \n        }\n        \n        let jsonParser = lexer.whiteSpace *> (jobject <|> jarray)\n        \n        let initialState = (\n            booleanCount: 0,\n            numberCount: 0,\n            stringCount: 0,\n            arrayCount: 0,\n            objectCount: 0,\n            nullCount: 0\n        )\n        \n        #if SWIFT_PACKAGE\n        \n        let bundle = Bundle(path: \"Tests/SwiftParsecTests\")!\n        \n        #else\n        \n        let bundle = Bundle(for: type(of: self))\n        \n        #endif\n        \n        let path = bundle.path(forResource: \"SampleJSON\", ofType: \"json\")!\n        \n        let jsonData = try! String(\n            contentsOfFile: path,\n            encoding: String.Encoding.utf8\n        );\n        \n        var statistics: JSONStatistics?\n        \n        let statisticsParser = jsonParser *>\n            GenericParser<String, JSONStatistics, JSONStatistics>.userState\n        self.measure {\n            do {\n                \n                let stats = try statisticsParser.run(\n                    userState: initialState,\n                    sourceName: \"\",\n                    input: jsonData\n                )\n                \n                statistics = stats\n                \n            } catch let error {\n                \n                XCTFail(String(describing: error))\n                \n            }\n            \n        }\n        \n        if let stats = statistics {\n            \n            XCTAssertEqual(3, stats.booleanCount)\n            XCTAssertEqual(1503, stats.numberCount)\n            XCTAssertEqual(3015, stats.stringCount)\n            XCTAssertEqual(999, stats.arrayCount)\n            XCTAssertEqual(1015, stats.objectCount)\n            XCTAssertEqual(2, stats.nullCount)\n            \n        }\n        \n    }\n    \n}\n\nextension JSONBenchmarkTests {\n    static var allTests: [(String, (JSONBenchmarkTests) -> () throws -> Void)] {\n        return [\n            (\"testJSONStatisticsParserPerformance\",\n             testJSONStatisticsParserPerformance)\n        ]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/PermutationTests.swift",
    "content": "//==============================================================================\n// PermutationTests.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-11-05.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nclass PermutationTests: XCTestCase {\n    \n    func testCollectionMethods() {\n        \n        var permutation: Permutation = [\n            \n            (StringParser.character(\"a\"), nil),\n            (StringParser.character(\"b\"), nil),\n            (StringParser.character(\"c\"), nil)\n            \n        ]\n\n        XCTAssertEqual(\n            permutation.count,\n            3,\n            \"Permutation.count should return 3.\"\n        )\n        \n        permutation.replaceSubrange(0..<1, with: [])\n        \n        XCTAssertEqual(\n            permutation.count,\n            2,\n            \"Permutation.replaceRange should remove first element.\"\n        )\n        \n    }\n    \n    func testPermutation() {\n        \n        let permutation: Permutation = [\n            \n            (StringParser.character(\"a\"), nil),\n            (StringParser.character(\"b\"), nil),\n            (StringParser.character(\"c\"), nil)\n            \n        ]\n        \n        let parser = permutation.makeParser().stringValue\n        \n        // Test for success.\n        let matching = [\"abc\", \"acb\", \"bac\", \"bca\", \"cab\", \"cba\"]\n        let errorMessage = \"Permutation.parser should succeed.\"\n        \n        testStringParserSuccess(parser, inputs: matching) { input, result in\n            \n            XCTAssertEqual(\n                \"abc\",\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test for failure.\n        let notMatching = [\n            \"bc\", \"cb\", \"ac\", \"ca\", \"ab\", \"ba\", \"aaa\", \"aab\", \"aac\", \"bbb\",\n            \"bba\", \"bbc\", \"ccc\", \"cca\", \"ccb\"\n        ]\n        let shouldFailMessage = \"Permutation.parser should fail.\"\n        \n        testStringParserFailure(parser, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testPermutationWithSeparator() {\n        \n        let permutation: Permutation = [\n            \n            (StringParser.character(\"a\"), nil),\n            (StringParser.character(\"b\"), nil),\n            (StringParser.character(\"c\"), nil),\n            \n        ]\n        \n        let comma = StringParser.character(\",\")\n        let parser = permutation.makeParser(separator: comma).stringValue\n        \n        // Test for success.\n        let matching = [\"a,b,c\", \"a,c,b\", \"b,a,c\", \"b,c,a\", \"c,a,b\", \"c,b,a\"]\n        let errorMessage = \"Permutation.parserWithSeparator should succeed.\"\n        \n        testStringParserSuccess(parser, inputs: matching) { input, result in\n            \n            XCTAssertEqual(\n                \"abc\",\n                result,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test for failure.\n        let notMatching = [\"ab,c\", \"a,cb\", \",b,a,c\", \"bca\"]\n        let shouldFailMessage =\n            \"Permutation.parserWithSeparator should fail.\"\n        \n        testStringParserFailure(parser, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testPermutationWithOptional() {\n        \n        let permutation: Permutation = [\n            \n            (StringParser.character(\"a\"), Character(\"_\")),\n            (StringParser.character(\"b\"), nil),\n            (StringParser.character(\"c\"), Character(\"?\"))\n            \n        ]\n        \n        let parser = permutation.makeParser().stringValue\n        \n        // Test for success.\n        let matching1 = [\"abc\", \"acb\", \"bac\", \"bca\", \"cab\", \"cba\"]\n        let expected1 = \"abc\"\n        let test1 = (matching1, expected1)\n        \n        let matching2 = [\"ab\", \"ba\"]\n        let expected2 = \"ab?\"\n        let test2 = (matching2, expected2)\n        \n        let matching3 = [\"bc\", \"cb\"]\n        let expected3 = \"_bc\"\n        let test3 = (matching3, expected3)\n        \n        let errorMessage = \"Permutation.parser should succeed.\"\n        \n        for (matching, expected) in [test1, test2, test3] {\n            \n            testStringParserSuccess(parser, inputs: matching) { input, result in\n                \n                XCTAssertEqual(\n                    expected,\n                    result,\n                    self.formatErrorMessage(\n                        errorMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n        // Test for failure.\n        let notMatching = [\"ac\", \"ca\", \"zbc\"]\n        let shouldFailMessage = \"Permutation.parser should fail.\"\n        \n        testStringParserFailure(parser, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testPermutationWithSeparatorAndOptional() {\n        \n        let permutation: Permutation = [\n            \n            (StringParser.character(\"a\"), nil),\n            (StringParser.character(\"b\"), Character(\"_\")),\n            (StringParser.character(\"c\"), nil),\n            (StringParser.character(\"d\"), nil),\n            \n        ]\n        \n        let comma = StringParser.character(\",\")\n        let parser = permutation.makeParser(separator: comma).stringValue\n        \n        // Test for success.\n        let matching1 = [\n            \"a,b,c,d\", \"a,c,b,d\", \"b,a,c,d\", \"b,c,a,d\", \"c,a,b,d\", \"c,b,a,d\"\n        ]\n        let expected1 = \"abcd\"\n        let test1 = (matching1, expected1)\n        \n        let matching2 = [\"a,c,d\", \"a,d,c\", \"c,a,d\", \"c,d,a\", \"d,a,c\", \"d,c,a\"]\n        let expected2 = \"a_cd\"\n        let test2 = (matching2, expected2)\n        \n        let errorMessage = \"Permutation.parser should succeed.\"\n        \n        for (matching, expected) in [test1, test2] {\n            \n            testStringParserSuccess(parser, inputs: matching) { input, result in\n                \n                XCTAssertEqual(\n                    expected,\n                    result,\n                    self.formatErrorMessage(\n                        errorMessage,\n                        input: input,\n                        result: result\n                    )\n                )\n                \n            }\n            \n        }\n        \n        // Test for failure.\n        let notMatching = [\"abcd\", \"acd\", \"ab,c,d\", \"abd\", \"cda\", \"dad\"]\n        let shouldFailMessage = \"Permutation.parser should fail.\"\n        \n        testStringParserFailure(parser, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testPermutationWithNil() {\n        \n        let lexer = GenericTokenParser<()>(\n            languageDefinition: LanguageDefinition.empty\n        )\n        let symbol = lexer.symbol\n        \n        let equal = symbol(\"=\")\n        \n        let quote = symbol(\"\\\"\")\n        let anyChar = StringParser.anyCharacter.manyTill(quote).stringValue\n        let value = quote *> anyChar.optional\n        \n        // Required parsers\n        let srcAttr = symbol(\"src\") *> equal *> value\n        let altAttr = symbol(\"alt\") *> equal *> value\n        \n        // Optional parsers\n        let longdescAttr = symbol(\"longdesc\") *> equal *> value\n        let heightAttr = symbol(\"height\") *> equal *> value\n        let widthAttr = symbol(\"width\") *> equal *> value\n        \n        var permutation = Permutation<String, (), String?>()\n        permutation.appendParser(srcAttr)\n        permutation.appendParser(altAttr)\n        permutation.appendOptionalParser(longdescAttr, otherwise: nil)\n        permutation.appendOptionalParser(heightAttr, otherwise: nil)\n        permutation.appendOptionalParser(widthAttr, otherwise: nil)\n        \n        let imgAttrs = permutation.makeParser()\n        \n        let img = symbol(\"img\") *> imgAttrs <* symbol(\"/\")\n        let imgTag = lexer.angles(img)\n        \n        // Test for success.\n        let matching = [\n            \"<img  src=\\\"test.jpg\\\" alt=\\\"A test image\\\" />\",\n            \"<img longdesc=\\\"A long description\\\"  src=\\\"test.jpg\\\" \" +\n                \"alt=\\\"A test image\\\" />\",\n            \"<img width=\\\"12\\\" src=\\\"test.jpg\\\"  alt=\\\"A test image\\\"/>\",\n            \"<img src=\\\"test.jpg\\\" height=\\\"120\\\" alt=\\\"A test image\\\"   />\",\n            \"<img height=\\\"120\\\" src=\\\"test.jpg\\\" alt=\\\"A test image\\\" \" +\n                \"width=\\\"12\\\" / >\",\n            \"<img src=\\\"test.jpg\\\" width=\\\"12\\\" \" +\n                \"longdesc=\\\"A long description\\\" alt=\\\"A test image\\\" \" +\n                \"height=\\\"120\\\" />\"\n        ]\n        \n        let expected: [[String?]] = [\n            [\"test.jpg\", \"A test image\", nil, nil, nil],\n            [\"test.jpg\", \"A test image\", \"A long description\", nil, nil],\n            [\"test.jpg\", \"A test image\", nil, nil, \"12\"],\n            [\"test.jpg\", \"A test image\", nil, \"120\", nil],\n            [\"test.jpg\", \"A test image\", nil, \"120\", \"12\"],\n            [\"test.jpg\", \"A test image\", \"A long description\", \"120\", \"12\"],\n        ]\n        \n        let errorMessage = \"Permutation.parser should succeed.\"\n        \n        var index = 0\n        testStringParserSuccess(imgTag, inputs: matching) { input, result in\n            \n            defer { index += 1 }\n            let isMatch = result == expected[index]\n            XCTAssert(\n                isMatch,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n        // Test for failure.\n        let notMatching = [\n            \"<imgwidth=\\\"12\\\" longdesc=\\\"A long description\\\" \" +\n                \"alt=\\\"A test image\\\" height=\\\"120\\\" />\"\n        ]\n        let shouldFailMessage = \"Permutation.parser should fail.\"\n        \n        testStringParserFailure(imgTag, inputs: notMatching) { input, result in\n            \n            XCTFail(\n                self.formatErrorMessage(\n                    shouldFailMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n}\n\n//==============================================================================\nprivate func ==(lhs: [String?], rhs: [String?]) -> Bool {\n    \n    return lhs.count == rhs.count && !zip(lhs, rhs).contains { $0 != $1 }\n    \n}\n\nextension PermutationTests {\n    static var allTests: [(String, (PermutationTests) -> () throws -> Void)] {\n        return [\n            (\"testCollectionMethods\", testCollectionMethods),\n            (\"testPermutation\", testPermutation),\n            (\"testPermutationWithSeparator\", testPermutationWithSeparator),\n            (\"testPermutationWithOptional\", testPermutationWithOptional),\n            (\"testPermutationWithSeparatorAndOptional\",\n             testPermutationWithSeparatorAndOptional),\n            (\"testPermutationWithNil\", testPermutationWithNil)\n        ]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/PositionTests.swift",
    "content": "//==============================================================================\n// PositionTests.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-11-13.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nclass PositionTests: XCTestCase {\n    \n    func testComparable() {\n        \n        let pos1 = SourcePosition(name: \"\", line: 1, column: 8)\n        let pos2 = SourcePosition(name: \"\", line: 2, column: 1)\n        let pos3 = SourcePosition(name: \"\", line: 1, column: 4)\n        \n        XCTAssert(pos1 < pos2, \"pos1 should be smaller than pos2.\")\n        XCTAssertFalse(pos2 < pos1, \"pos2 should be greater than pos1.\")\n        XCTAssert(pos1 == pos1, \"pos1 should be equal to itself.\")\n        XCTAssert(pos1 > pos3, \"pos1 should be greater than pos3.\")\n        XCTAssertFalse(pos3 > pos1, \"pos3 should be smaller than pos1.\")\n        \n    }\n    \n    func testColumnPosition() {\n        \n        let str = \"1234\"\n        let expectedColumn = str.count + 1\n        \n        let strParser = StringParser.string(str)\n        let positionParser = strParser *>\n            GenericParser<String, (), SourcePosition>.sourcePosition\n        \n        let errorMessage = \"GenericParser.sourcePosition should return \" +\n            \"column value equal to \\\"\\(expectedColumn)\\\".\"\n        \n        testStringParserSuccess(positionParser, inputs: [str])\n        { input, result in\n            \n            XCTAssertEqual(\n                expectedColumn,\n                result.column,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testLineColumnPosition() {\n        \n        let str = \"1\\n2\\n3\"\n        let expectedLine = 3\n        let expectedColumn = 2\n        \n        let strParser = StringParser.string(str)\n        let positionParser = strParser *>\n            GenericParser<String, (), SourcePosition>.sourcePosition\n        \n        let errorMessage = \"GenericParser.sourcePosition should return \" +\n            \"line value equal to \\\"\\(expectedLine)\\\" and column value equal \" +\n            \"to \\\"\\(expectedLine)\\\".\"\n        \n        testStringParserSuccess(positionParser, inputs: [str])\n        { input, result in\n            \n            let positionEqual = expectedLine == result.line &&\n                expectedColumn == result.column\n            \n            XCTAssert(\n                positionEqual,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n    func testTabPosition() {\n        \n        let str = \"1\\t3\"\n        let expectedColumn = 10\n        \n        let strParser = StringParser.string(str)\n        let positionParser = strParser *>\n            GenericParser<String, (), SourcePosition>.sourcePosition\n        \n        let errorMessage = \"GenericParser.sourcePosition should return \" +\n            \"column value equal to \\\"\\(expectedColumn)\\\".\"\n        \n        testStringParserSuccess(positionParser, inputs: [str])\n        { input, result in\n            \n            XCTAssertEqual(\n                expectedColumn,\n                result.column,\n                self.formatErrorMessage(\n                    errorMessage,\n                    input: input,\n                    result: result\n                )\n            )\n            \n        }\n        \n    }\n    \n}\n\nextension PositionTests {\n    static var allTests: [(String, (PositionTests) -> () throws -> Void)] {\n        return [\n            (\"testComparable\", testComparable),\n            (\"testColumnPosition\", testColumnPosition),\n            (\"testLineColumnPosition\", testLineColumnPosition),\n            (\"testTabPosition\", testTabPosition)\n        ]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/SampleJSON.json",
    "content": "{\n    \"name\":\"Product\",\n    \"properties\":\n    {\n        \"id\":\n        {\n            \"type\":\"number\",\n            \"description\":\"Product identifier\",\n            \"required\":true\n        },\n        \"name\":\n        {\n            \"type\":\"string\",\n            \"description\":\"Name of the product\",\n            \"required\":true\n        },\n        \"price\":\n        {\n            \"type\":\"number\",\n            \"minimum\":0,\n            \"required\":true\n        },\n        \"reviews\":\n        {\n            \"type\":\"array\",\n            \"items\":\n            {\n                \"type\":\"object\",\n                \"properties\":\n                {\n                    \"user\":\n                    {\n                        \"type\":\"string\",\n                        \"description\":\"Name of the user\"\n                    },\n                    \"review\":\n                    {\n                        \"type\":\"string\",\n                        \"description\":\"User comments\"\n                    },\n                    \"ratings\":\n                    {\n                        \"type\":\"number\",\n                        \"description\":\"Rating from 1 to 5\"\n                    }\n                }\n            }\n        },\n        \"tags\":\n        {\n            \"type\":\"array\",\n            \"items\":\n            {\n                \"type\":\"string\"\n            }\n        }\n    },\n    \"records\":\n    [\n        {\n            \"id\":1,\n            \"name\":\"Product 1\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 1\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":2,\n            \"name\":\"Product 2\",\n            \"price\":99.99,\n            \"reviews\":null,\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":3,\n            \"name\":\"Product 3\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 3\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":null\n        },\n        {\n            \"id\":4,\n            \"name\":\"Product 4\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 4\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":5,\n            \"name\":\"Product 5\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 5\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":6,\n            \"name\":\"Product 6\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 6\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":7,\n            \"name\":\"Product 7\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 7\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":8,\n            \"name\":\"Product 8\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 8\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":9,\n            \"name\":\"Product 9\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 9\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":10,\n            \"name\":\"Product 10\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 10\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":11,\n            \"name\":\"Product 11\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 11\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":12,\n            \"name\":\"Product 12\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 12\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":13,\n            \"name\":\"Product 13\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 13\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":14,\n            \"name\":\"Product 14\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 14\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":15,\n            \"name\":\"Product 15\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 15\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":16,\n            \"name\":\"Product 16\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 16\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":17,\n            \"name\":\"Product 17\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 17\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":18,\n            \"name\":\"Product 18\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 18\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":19,\n            \"name\":\"Product 19\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 19\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":20,\n            \"name\":\"Product 20\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 20\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":21,\n            \"name\":\"Product 21\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 21\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":22,\n            \"name\":\"Product 22\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 22\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":23,\n            \"name\":\"Product 23\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 23\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":24,\n            \"name\":\"Product 24\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 24\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":25,\n            \"name\":\"Product 25\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 25\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":26,\n            \"name\":\"Product 26\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 26\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":27,\n            \"name\":\"Product 27\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 27\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":28,\n            \"name\":\"Product 28\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 28\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":29,\n            \"name\":\"Product 29\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 29\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":30,\n            \"name\":\"Product 30\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 30\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":31,\n            \"name\":\"Product 31\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 31\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":32,\n            \"name\":\"Product 32\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 32\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":33,\n            \"name\":\"Product 33\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 33\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":34,\n            \"name\":\"Product 34\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 34\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":35,\n            \"name\":\"Product 35\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 35\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":36,\n            \"name\":\"Product 36\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 36\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":37,\n            \"name\":\"Product 37\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 37\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":38,\n            \"name\":\"Product 38\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 38\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":39,\n            \"name\":\"Product 39\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 39\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":40,\n            \"name\":\"Product 40\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 40\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":41,\n            \"name\":\"Product 41\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 41\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":42,\n            \"name\":\"Product 42\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 42\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":43,\n            \"name\":\"Product 43\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 43\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":44,\n            \"name\":\"Product 44\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 44\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":45,\n            \"name\":\"Product 45\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 45\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":46,\n            \"name\":\"Product 46\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 46\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":47,\n            \"name\":\"Product 47\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 47\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":48,\n            \"name\":\"Product 48\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 48\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":49,\n            \"name\":\"Product 49\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 49\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":50,\n            \"name\":\"Product 50\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 50\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":51,\n            \"name\":\"Product 51\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 51\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":52,\n            \"name\":\"Product 52\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 52\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":53,\n            \"name\":\"Product 53\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 53\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":54,\n            \"name\":\"Product 54\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 54\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":55,\n            \"name\":\"Product 55\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 55\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":56,\n            \"name\":\"Product 56\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 56\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":57,\n            \"name\":\"Product 57\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 57\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":58,\n            \"name\":\"Product 58\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 58\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":59,\n            \"name\":\"Product 59\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 59\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":60,\n            \"name\":\"Product 60\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 60\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":61,\n            \"name\":\"Product 61\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 61\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":62,\n            \"name\":\"Product 62\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 62\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":63,\n            \"name\":\"Product 63\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 63\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":64,\n            \"name\":\"Product 64\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 64\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":65,\n            \"name\":\"Product 65\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 65\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":66,\n            \"name\":\"Product 66\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 66\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":67,\n            \"name\":\"Product 67\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 67\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":68,\n            \"name\":\"Product 68\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 68\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":69,\n            \"name\":\"Product 69\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 69\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":70,\n            \"name\":\"Product 70\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 70\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":71,\n            \"name\":\"Product 71\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 71\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":72,\n            \"name\":\"Product 72\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 72\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":73,\n            \"name\":\"Product 73\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 73\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":74,\n            \"name\":\"Product 74\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 74\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":75,\n            \"name\":\"Product 75\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 75\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":76,\n            \"name\":\"Product 76\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 76\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":77,\n            \"name\":\"Product 77\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 77\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":78,\n            \"name\":\"Product 78\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 78\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":79,\n            \"name\":\"Product 79\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 79\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":80,\n            \"name\":\"Product 80\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 80\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":81,\n            \"name\":\"Product 81\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 81\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":82,\n            \"name\":\"Product 82\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 82\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":83,\n            \"name\":\"Product 83\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 83\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":84,\n            \"name\":\"Product 84\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 84\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":85,\n            \"name\":\"Product 85\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 85\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":86,\n            \"name\":\"Product 86\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 86\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":87,\n            \"name\":\"Product 87\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 87\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":88,\n            \"name\":\"Product 88\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 88\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":89,\n            \"name\":\"Product 89\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 89\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":90,\n            \"name\":\"Product 90\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 90\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":91,\n            \"name\":\"Product 91\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 91\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":92,\n            \"name\":\"Product 92\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 92\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":93,\n            \"name\":\"Product 93\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 93\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":94,\n            \"name\":\"Product 94\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 94\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":95,\n            \"name\":\"Product 95\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 95\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":96,\n            \"name\":\"Product 96\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 96\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":97,\n            \"name\":\"Product 97\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 97\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":98,\n            \"name\":\"Product 98\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 98\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":99,\n            \"name\":\"Product 99\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 99\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":100,\n            \"name\":\"Product 100\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 100\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":101,\n            \"name\":\"Product 101\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 101\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":102,\n            \"name\":\"Product 102\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 102\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":103,\n            \"name\":\"Product 103\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 103\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":104,\n            \"name\":\"Product 104\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 104\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":105,\n            \"name\":\"Product 105\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 105\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":106,\n            \"name\":\"Product 106\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 106\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":107,\n            \"name\":\"Product 107\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 107\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":108,\n            \"name\":\"Product 108\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 108\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":109,\n            \"name\":\"Product 109\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 109\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":110,\n            \"name\":\"Product 110\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 110\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":111,\n            \"name\":\"Product 111\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 111\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":112,\n            \"name\":\"Product 112\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 112\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":113,\n            \"name\":\"Product 113\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 113\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":114,\n            \"name\":\"Product 114\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 114\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":115,\n            \"name\":\"Product 115\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 115\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":116,\n            \"name\":\"Product 116\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 116\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":117,\n            \"name\":\"Product 117\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 117\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":118,\n            \"name\":\"Product 118\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 118\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":119,\n            \"name\":\"Product 119\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 119\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":120,\n            \"name\":\"Product 120\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 120\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":121,\n            \"name\":\"Product 121\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 121\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":122,\n            \"name\":\"Product 122\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 122\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":123,\n            \"name\":\"Product 123\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 123\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":124,\n            \"name\":\"Product 124\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 124\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":125,\n            \"name\":\"Product 125\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 125\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":126,\n            \"name\":\"Product 126\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 126\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":127,\n            \"name\":\"Product 127\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 127\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":128,\n            \"name\":\"Product 128\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 128\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":129,\n            \"name\":\"Product 129\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 129\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":130,\n            \"name\":\"Product 130\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 130\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":131,\n            \"name\":\"Product 131\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 131\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":132,\n            \"name\":\"Product 132\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 132\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":133,\n            \"name\":\"Product 133\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 133\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":134,\n            \"name\":\"Product 134\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 134\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":135,\n            \"name\":\"Product 135\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 135\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":136,\n            \"name\":\"Product 136\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 136\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":137,\n            \"name\":\"Product 137\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 137\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":138,\n            \"name\":\"Product 138\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 138\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":139,\n            \"name\":\"Product 139\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 139\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":140,\n            \"name\":\"Product 140\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 140\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":141,\n            \"name\":\"Product 141\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 141\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":142,\n            \"name\":\"Product 142\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 142\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":143,\n            \"name\":\"Product 143\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 143\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":144,\n            \"name\":\"Product 144\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 144\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":145,\n            \"name\":\"Product 145\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 145\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":146,\n            \"name\":\"Product 146\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 146\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":147,\n            \"name\":\"Product 147\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 147\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":148,\n            \"name\":\"Product 148\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 148\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":149,\n            \"name\":\"Product 149\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 149\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":150,\n            \"name\":\"Product 150\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 150\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":151,\n            \"name\":\"Product 151\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 151\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":152,\n            \"name\":\"Product 152\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 152\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":153,\n            \"name\":\"Product 153\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 153\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":154,\n            \"name\":\"Product 154\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 154\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":155,\n            \"name\":\"Product 155\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 155\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":156,\n            \"name\":\"Product 156\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 156\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":157,\n            \"name\":\"Product 157\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 157\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":158,\n            \"name\":\"Product 158\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 158\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":159,\n            \"name\":\"Product 159\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 159\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":160,\n            \"name\":\"Product 160\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 160\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":161,\n            \"name\":\"Product 161\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 161\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":162,\n            \"name\":\"Product 162\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 162\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":163,\n            \"name\":\"Product 163\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 163\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":164,\n            \"name\":\"Product 164\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 164\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":165,\n            \"name\":\"Product 165\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 165\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":166,\n            \"name\":\"Product 166\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 166\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":167,\n            \"name\":\"Product 167\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 167\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":168,\n            \"name\":\"Product 168\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 168\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":169,\n            \"name\":\"Product 169\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 169\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":170,\n            \"name\":\"Product 170\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 170\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":171,\n            \"name\":\"Product 171\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 171\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":172,\n            \"name\":\"Product 172\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 172\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":173,\n            \"name\":\"Product 173\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 173\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":174,\n            \"name\":\"Product 174\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 174\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":175,\n            \"name\":\"Product 175\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 175\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":176,\n            \"name\":\"Product 176\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 176\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":177,\n            \"name\":\"Product 177\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 177\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":178,\n            \"name\":\"Product 178\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 178\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":179,\n            \"name\":\"Product 179\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 179\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":180,\n            \"name\":\"Product 180\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 180\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":181,\n            \"name\":\"Product 181\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 181\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":182,\n            \"name\":\"Product 182\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 182\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":183,\n            \"name\":\"Product 183\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 183\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":184,\n            \"name\":\"Product 184\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 184\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":185,\n            \"name\":\"Product 185\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 185\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":186,\n            \"name\":\"Product 186\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 186\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":187,\n            \"name\":\"Product 187\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 187\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":188,\n            \"name\":\"Product 188\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 188\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":189,\n            \"name\":\"Product 189\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 189\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":190,\n            \"name\":\"Product 190\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 190\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":191,\n            \"name\":\"Product 191\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 191\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":192,\n            \"name\":\"Product 192\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 192\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":193,\n            \"name\":\"Product 193\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 193\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":194,\n            \"name\":\"Product 194\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 194\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":195,\n            \"name\":\"Product 195\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 195\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":196,\n            \"name\":\"Product 196\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 196\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":197,\n            \"name\":\"Product 197\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 197\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":198,\n            \"name\":\"Product 198\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 198\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":199,\n            \"name\":\"Product 199\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 199\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":200,\n            \"name\":\"Product 200\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 200\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":201,\n            \"name\":\"Product 201\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 201\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":202,\n            \"name\":\"Product 202\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 202\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":203,\n            \"name\":\"Product 203\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 203\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":204,\n            \"name\":\"Product 204\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 204\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":205,\n            \"name\":\"Product 205\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 205\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":206,\n            \"name\":\"Product 206\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 206\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":207,\n            \"name\":\"Product 207\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 207\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":208,\n            \"name\":\"Product 208\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 208\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":209,\n            \"name\":\"Product 209\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 209\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":210,\n            \"name\":\"Product 210\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 210\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":211,\n            \"name\":\"Product 211\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 211\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":212,\n            \"name\":\"Product 212\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 212\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":213,\n            \"name\":\"Product 213\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 213\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":214,\n            \"name\":\"Product 214\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 214\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":215,\n            \"name\":\"Product 215\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 215\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":216,\n            \"name\":\"Product 216\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 216\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":217,\n            \"name\":\"Product 217\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 217\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":218,\n            \"name\":\"Product 218\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 218\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":219,\n            \"name\":\"Product 219\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 219\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":220,\n            \"name\":\"Product 220\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 220\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":221,\n            \"name\":\"Product 221\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 221\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":222,\n            \"name\":\"Product 222\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 222\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":223,\n            \"name\":\"Product 223\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 223\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":224,\n            \"name\":\"Product 224\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 224\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":225,\n            \"name\":\"Product 225\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 225\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":226,\n            \"name\":\"Product 226\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 226\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":227,\n            \"name\":\"Product 227\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 227\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":228,\n            \"name\":\"Product 228\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 228\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":229,\n            \"name\":\"Product 229\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 229\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":230,\n            \"name\":\"Product 230\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 230\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":231,\n            \"name\":\"Product 231\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 231\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":232,\n            \"name\":\"Product 232\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 232\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":233,\n            \"name\":\"Product 233\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 233\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":234,\n            \"name\":\"Product 234\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 234\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":235,\n            \"name\":\"Product 235\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 235\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":236,\n            \"name\":\"Product 236\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 236\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":237,\n            \"name\":\"Product 237\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 237\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":238,\n            \"name\":\"Product 238\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 238\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":239,\n            \"name\":\"Product 239\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 239\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":240,\n            \"name\":\"Product 240\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 240\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":241,\n            \"name\":\"Product 241\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 241\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":242,\n            \"name\":\"Product 242\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 242\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":243,\n            \"name\":\"Product 243\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 243\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":244,\n            \"name\":\"Product 244\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 244\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":245,\n            \"name\":\"Product 245\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 245\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":246,\n            \"name\":\"Product 246\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 246\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":247,\n            \"name\":\"Product 247\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 247\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":248,\n            \"name\":\"Product 248\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 248\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":249,\n            \"name\":\"Product 249\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 249\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":250,\n            \"name\":\"Product 250\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 250\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":251,\n            \"name\":\"Product 251\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 251\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":252,\n            \"name\":\"Product 252\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 252\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":253,\n            \"name\":\"Product 253\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 253\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":254,\n            \"name\":\"Product 254\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 254\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":255,\n            \"name\":\"Product 255\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 255\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":256,\n            \"name\":\"Product 256\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 256\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":257,\n            \"name\":\"Product 257\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 257\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":258,\n            \"name\":\"Product 258\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 258\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":259,\n            \"name\":\"Product 259\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 259\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":260,\n            \"name\":\"Product 260\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 260\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":261,\n            \"name\":\"Product 261\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 261\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":262,\n            \"name\":\"Product 262\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 262\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":263,\n            \"name\":\"Product 263\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 263\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":264,\n            \"name\":\"Product 264\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 264\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":265,\n            \"name\":\"Product 265\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 265\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":266,\n            \"name\":\"Product 266\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 266\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":267,\n            \"name\":\"Product 267\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 267\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":268,\n            \"name\":\"Product 268\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 268\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":269,\n            \"name\":\"Product 269\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 269\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":270,\n            \"name\":\"Product 270\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 270\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":271,\n            \"name\":\"Product 271\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 271\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":272,\n            \"name\":\"Product 272\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 272\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":273,\n            \"name\":\"Product 273\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 273\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":274,\n            \"name\":\"Product 274\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 274\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":275,\n            \"name\":\"Product 275\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 275\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":276,\n            \"name\":\"Product 276\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 276\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":277,\n            \"name\":\"Product 277\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 277\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":278,\n            \"name\":\"Product 278\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 278\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":279,\n            \"name\":\"Product 279\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 279\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":280,\n            \"name\":\"Product 280\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 280\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":281,\n            \"name\":\"Product 281\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 281\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":282,\n            \"name\":\"Product 282\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 282\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":283,\n            \"name\":\"Product 283\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 283\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":284,\n            \"name\":\"Product 284\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 284\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":285,\n            \"name\":\"Product 285\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 285\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":286,\n            \"name\":\"Product 286\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 286\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":287,\n            \"name\":\"Product 287\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 287\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":288,\n            \"name\":\"Product 288\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 288\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":289,\n            \"name\":\"Product 289\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 289\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":290,\n            \"name\":\"Product 290\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 290\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":291,\n            \"name\":\"Product 291\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 291\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":292,\n            \"name\":\"Product 292\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 292\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":293,\n            \"name\":\"Product 293\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 293\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":294,\n            \"name\":\"Product 294\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 294\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":295,\n            \"name\":\"Product 295\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 295\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":296,\n            \"name\":\"Product 296\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 296\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":297,\n            \"name\":\"Product 297\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 297\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":298,\n            \"name\":\"Product 298\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 298\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":299,\n            \"name\":\"Product 299\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 299\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":300,\n            \"name\":\"Product 300\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 300\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":301,\n            \"name\":\"Product 301\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 301\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":302,\n            \"name\":\"Product 302\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 302\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":303,\n            \"name\":\"Product 303\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 303\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":304,\n            \"name\":\"Product 304\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 304\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":305,\n            \"name\":\"Product 305\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 305\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":306,\n            \"name\":\"Product 306\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 306\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":307,\n            \"name\":\"Product 307\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 307\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":308,\n            \"name\":\"Product 308\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 308\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":309,\n            \"name\":\"Product 309\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 309\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":310,\n            \"name\":\"Product 310\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 310\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":311,\n            \"name\":\"Product 311\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 311\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":312,\n            \"name\":\"Product 312\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 312\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":313,\n            \"name\":\"Product 313\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 313\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":314,\n            \"name\":\"Product 314\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 314\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":315,\n            \"name\":\"Product 315\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 315\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":316,\n            \"name\":\"Product 316\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 316\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":317,\n            \"name\":\"Product 317\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 317\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":318,\n            \"name\":\"Product 318\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 318\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":319,\n            \"name\":\"Product 319\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 319\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":320,\n            \"name\":\"Product 320\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 320\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":321,\n            \"name\":\"Product 321\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 321\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":322,\n            \"name\":\"Product 322\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 322\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":323,\n            \"name\":\"Product 323\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 323\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":324,\n            \"name\":\"Product 324\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 324\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":325,\n            \"name\":\"Product 325\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 325\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":326,\n            \"name\":\"Product 326\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 326\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":327,\n            \"name\":\"Product 327\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 327\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":328,\n            \"name\":\"Product 328\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 328\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":329,\n            \"name\":\"Product 329\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 329\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":330,\n            \"name\":\"Product 330\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 330\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":331,\n            \"name\":\"Product 331\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 331\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":332,\n            \"name\":\"Product 332\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 332\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":333,\n            \"name\":\"Product 333\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 333\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":334,\n            \"name\":\"Product 334\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 334\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":335,\n            \"name\":\"Product 335\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 335\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":336,\n            \"name\":\"Product 336\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 336\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":337,\n            \"name\":\"Product 337\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 337\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":338,\n            \"name\":\"Product 338\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 338\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":339,\n            \"name\":\"Product 339\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 339\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":340,\n            \"name\":\"Product 340\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 340\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":341,\n            \"name\":\"Product 341\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 341\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":342,\n            \"name\":\"Product 342\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 342\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":343,\n            \"name\":\"Product 343\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 343\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":344,\n            \"name\":\"Product 344\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 344\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":345,\n            \"name\":\"Product 345\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 345\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":346,\n            \"name\":\"Product 346\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 346\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":347,\n            \"name\":\"Product 347\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 347\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":348,\n            \"name\":\"Product 348\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 348\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":349,\n            \"name\":\"Product 349\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 349\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":350,\n            \"name\":\"Product 350\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 350\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":351,\n            \"name\":\"Product 351\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 351\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":352,\n            \"name\":\"Product 352\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 352\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":353,\n            \"name\":\"Product 353\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 353\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":354,\n            \"name\":\"Product 354\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 354\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":355,\n            \"name\":\"Product 355\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 355\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":356,\n            \"name\":\"Product 356\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 356\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":357,\n            \"name\":\"Product 357\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 357\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":358,\n            \"name\":\"Product 358\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 358\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":359,\n            \"name\":\"Product 359\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 359\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":360,\n            \"name\":\"Product 360\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 360\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":361,\n            \"name\":\"Product 361\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 361\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":362,\n            \"name\":\"Product 362\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 362\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":363,\n            \"name\":\"Product 363\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 363\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":364,\n            \"name\":\"Product 364\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 364\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":365,\n            \"name\":\"Product 365\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 365\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":366,\n            \"name\":\"Product 366\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 366\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":367,\n            \"name\":\"Product 367\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 367\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":368,\n            \"name\":\"Product 368\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 368\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":369,\n            \"name\":\"Product 369\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 369\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":370,\n            \"name\":\"Product 370\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 370\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":371,\n            \"name\":\"Product 371\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 371\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":372,\n            \"name\":\"Product 372\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 372\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":373,\n            \"name\":\"Product 373\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 373\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":374,\n            \"name\":\"Product 374\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 374\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":375,\n            \"name\":\"Product 375\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 375\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":376,\n            \"name\":\"Product 376\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 376\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":377,\n            \"name\":\"Product 377\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 377\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":378,\n            \"name\":\"Product 378\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 378\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":379,\n            \"name\":\"Product 379\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 379\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":380,\n            \"name\":\"Product 380\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 380\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":381,\n            \"name\":\"Product 381\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 381\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":382,\n            \"name\":\"Product 382\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 382\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":383,\n            \"name\":\"Product 383\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 383\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":384,\n            \"name\":\"Product 384\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 384\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":385,\n            \"name\":\"Product 385\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 385\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":386,\n            \"name\":\"Product 386\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 386\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":387,\n            \"name\":\"Product 387\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 387\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":388,\n            \"name\":\"Product 388\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 388\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":389,\n            \"name\":\"Product 389\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 389\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":390,\n            \"name\":\"Product 390\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 390\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":391,\n            \"name\":\"Product 391\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 391\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":392,\n            \"name\":\"Product 392\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 392\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":393,\n            \"name\":\"Product 393\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 393\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":394,\n            \"name\":\"Product 394\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 394\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":395,\n            \"name\":\"Product 395\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 395\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":396,\n            \"name\":\"Product 396\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 396\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":397,\n            \"name\":\"Product 397\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 397\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":398,\n            \"name\":\"Product 398\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 398\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":399,\n            \"name\":\"Product 399\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 399\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":400,\n            \"name\":\"Product 400\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 400\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":401,\n            \"name\":\"Product 401\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 401\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":402,\n            \"name\":\"Product 402\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 402\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":403,\n            \"name\":\"Product 403\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 403\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":404,\n            \"name\":\"Product 404\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 404\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":405,\n            \"name\":\"Product 405\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 405\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":406,\n            \"name\":\"Product 406\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 406\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":407,\n            \"name\":\"Product 407\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 407\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":408,\n            \"name\":\"Product 408\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 408\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":409,\n            \"name\":\"Product 409\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 409\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":410,\n            \"name\":\"Product 410\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 410\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":411,\n            \"name\":\"Product 411\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 411\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":412,\n            \"name\":\"Product 412\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 412\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":413,\n            \"name\":\"Product 413\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 413\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":414,\n            \"name\":\"Product 414\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 414\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":415,\n            \"name\":\"Product 415\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 415\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":416,\n            \"name\":\"Product 416\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 416\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":417,\n            \"name\":\"Product 417\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 417\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":418,\n            \"name\":\"Product 418\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 418\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":419,\n            \"name\":\"Product 419\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 419\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":420,\n            \"name\":\"Product 420\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 420\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":421,\n            \"name\":\"Product 421\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 421\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":422,\n            \"name\":\"Product 422\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 422\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":423,\n            \"name\":\"Product 423\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 423\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":424,\n            \"name\":\"Product 424\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 424\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":425,\n            \"name\":\"Product 425\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 425\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":426,\n            \"name\":\"Product 426\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 426\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":427,\n            \"name\":\"Product 427\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 427\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":428,\n            \"name\":\"Product 428\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 428\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":429,\n            \"name\":\"Product 429\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 429\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":430,\n            \"name\":\"Product 430\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 430\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":431,\n            \"name\":\"Product 431\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 431\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":432,\n            \"name\":\"Product 432\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 432\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":433,\n            \"name\":\"Product 433\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 433\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":434,\n            \"name\":\"Product 434\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 434\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":435,\n            \"name\":\"Product 435\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 435\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":436,\n            \"name\":\"Product 436\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 436\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":437,\n            \"name\":\"Product 437\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 437\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":438,\n            \"name\":\"Product 438\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 438\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":439,\n            \"name\":\"Product 439\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 439\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":440,\n            \"name\":\"Product 440\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 440\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":441,\n            \"name\":\"Product 441\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 441\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":442,\n            \"name\":\"Product 442\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 442\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":443,\n            \"name\":\"Product 443\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 443\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":444,\n            \"name\":\"Product 444\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 444\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":445,\n            \"name\":\"Product 445\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 445\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":446,\n            \"name\":\"Product 446\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 446\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":447,\n            \"name\":\"Product 447\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 447\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":448,\n            \"name\":\"Product 448\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 448\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":449,\n            \"name\":\"Product 449\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 449\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":450,\n            \"name\":\"Product 450\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 450\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":451,\n            \"name\":\"Product 451\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 451\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":452,\n            \"name\":\"Product 452\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 452\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":453,\n            \"name\":\"Product 453\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 453\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":454,\n            \"name\":\"Product 454\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 454\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":455,\n            \"name\":\"Product 455\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 455\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":456,\n            \"name\":\"Product 456\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 456\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":457,\n            \"name\":\"Product 457\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 457\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":458,\n            \"name\":\"Product 458\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 458\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":459,\n            \"name\":\"Product 459\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 459\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":460,\n            \"name\":\"Product 460\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 460\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":461,\n            \"name\":\"Product 461\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 461\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":462,\n            \"name\":\"Product 462\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 462\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":463,\n            \"name\":\"Product 463\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 463\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":464,\n            \"name\":\"Product 464\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 464\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":465,\n            \"name\":\"Product 465\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 465\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":466,\n            \"name\":\"Product 466\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 466\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":467,\n            \"name\":\"Product 467\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 467\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":468,\n            \"name\":\"Product 468\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 468\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":469,\n            \"name\":\"Product 469\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 469\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":470,\n            \"name\":\"Product 470\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 470\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":471,\n            \"name\":\"Product 471\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 471\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":472,\n            \"name\":\"Product 472\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 472\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":473,\n            \"name\":\"Product 473\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 473\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":474,\n            \"name\":\"Product 474\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 474\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":475,\n            \"name\":\"Product 475\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 475\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":476,\n            \"name\":\"Product 476\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 476\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":477,\n            \"name\":\"Product 477\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 477\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":478,\n            \"name\":\"Product 478\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 478\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":479,\n            \"name\":\"Product 479\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 479\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":480,\n            \"name\":\"Product 480\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 480\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":481,\n            \"name\":\"Product 481\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 481\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":482,\n            \"name\":\"Product 482\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 482\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":483,\n            \"name\":\"Product 483\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 483\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":484,\n            \"name\":\"Product 484\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 484\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":485,\n            \"name\":\"Product 485\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 485\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":486,\n            \"name\":\"Product 486\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 486\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":487,\n            \"name\":\"Product 487\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 487\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":488,\n            \"name\":\"Product 488\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 488\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":489,\n            \"name\":\"Product 489\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 489\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":490,\n            \"name\":\"Product 490\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 490\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":491,\n            \"name\":\"Product 491\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 491\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":492,\n            \"name\":\"Product 492\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 492\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":493,\n            \"name\":\"Product 493\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 493\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":494,\n            \"name\":\"Product 494\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 494\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":495,\n            \"name\":\"Product 495\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 495\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":496,\n            \"name\":\"Product 496\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 496\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":497,\n            \"name\":\"Product 497\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 497\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":498,\n            \"name\":\"Product 498\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 498\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":499,\n            \"name\":\"Product 499\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 499\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             },\n             {\n                \"user\":\"User 499-a\",\n                \"review\":\"Product review a\",\n                \"ratings\":2\n             },\n             {\n                \"user\":\"User 499-b\",\n                \"review\":\"Product review b\",\n                \"ratings\":4\n             }\n            ],\n            \"tags\":[\"tag1\", \"tag2\", \"tag3\"]\n        },\n        {\n            \"id\":500,\n            \"name\":\"Product 500\",\n            \"price\":99.99,\n            \"reviews\":\n            [\n             {\n                \"user\":\"User 500\",\n                \"review\":\"Product review\",\n                \"ratings\":3\n             },\n             {\n                \"user\":\"User 500-a\",\n                \"review\":\"Product review a\",\n                \"ratings\":5\n             }\n            ],\n            \"tags\":[\"tag1\"]\n        }\n     ]\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/StringTests.swift",
    "content": "//==============================================================================\n// StringTests.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2016-05-25.\n// Copyright © 2016 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nclass StringTests: XCTestCase {\n\n    func testLast() {\n        \n        let str = \"1234\"\n        XCTAssertEqual(\n            \"4\",\n            str.last!,\n            \"`str.last` should return \\\"4\\\".\"\n        )\n        \n        let emptyStr = \"\"\n        XCTAssertNil(\n            emptyStr.last,\n            \"`emptyStr.last` should return `nil`.\"\n        )\n        \n    }\n\n}\n\nextension StringTests {\n    static var allTests: [(String, (StringTests) -> () throws -> Void)] {\n        return [(\"testLast\", testLast)]\n    }\n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/TestUtilities.swift",
    "content": "//==============================================================================\n// TestUtilities.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2015-09-21.\n// Copyright © 2015 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nextension XCTestCase {\n    \n    /// Run `parser` in a `do-catch` block on the supplied input strings. The\n    /// assertions are performed in the `assert` function. If an error is thrown\n    /// it is reported with `XCTFail()`.\n    func testStringParserSuccess<Result, Input: Collection>(\n        _ parser: GenericParser<String, (), Result>,\n        inputs: Input, assert: (String, Result) -> Void\n    ) where Input.Iterator.Element == String {\n        \n        do {\n            \n            for input in inputs {\n                \n                let result = try parser.run(sourceName: \"\", input: input)\n                assert(input, result)\n                \n            }\n            \n        } catch let parseError as ParseError {\n            \n            XCTFail(String(describing: parseError))\n            \n        } catch let error {\n            \n            XCTFail(String(describing: error))\n            \n        }\n        \n    }\n    \n    /// Run `parser` in a `do-catch` block. The assertions are performed in the\n    /// `assert` function. If an error is thrown it is reported with\n    /// `XCTFail()`.\n    func testParserSuccess<Result>(\n        _ parser: GenericParser<String, (), Result>,\n        assert: (String, Result) -> Void\n    ) {\n        \n        testStringParserSuccess(parser, inputs: [\"\"], assert: assert)\n        \n    }\n    \n    /// Run `parser` in a `do-catch` block on the supplied input strings. The\n    /// assertions are performed in the `assert` function. If an error is thrown\n    /// it is reported with `XCTFail()`.\n    func testStringParserFailure<Result, Input: Collection>(\n        _ parser: GenericParser<String, (), Result>,\n        inputs: Input,\n        assert: (String, Result) -> Void\n    ) where Input.Iterator.Element == String {\n        \n        for input in inputs {\n            \n            do {\n                \n                let result = try parser.run(sourceName: \"\", input: input)\n                assert(input, result)\n                \n            } catch is ParseError {\n                \n                // Parser failed as expected.\n                \n            } catch let error {\n                \n                XCTFail(String(describing: error))\n                \n            }\n            \n        }\n        \n    }\n    \n    func formatErrorMessage<Result>(\n        _ message: String,\n        input: String,\n        result: Result\n    ) -> String {\n        \n        return message + \"\\nInput: \" + input + \"\\nResult: \" +\n            String(describing: result)\n        \n    }\n    \n}\n"
  },
  {
    "path": "Tests/SwiftParsecTests/UnicodeScalarTests.swift",
    "content": "//==============================================================================\n// UnicodeScalarTests.swift\n// SwiftParsec\n//\n// Created by David Dufresne on 2016-05-10.\n// Copyright © 2016 David Dufresne. All rights reserved.\n//==============================================================================\n\nimport XCTest\n@testable import SwiftParsec\n\nprivate let maxCodePointValue = 0x10FFFF\nprivate let minSurrogatePairValue = 0xD800\nprivate let maxSurrogatePairValue = 0xDFFF\n\nclass UnicodeScalarTests: XCTestCase {\n\n    func testFromInt() {\n        \n        // Test boundary conditions\n        \n        let aboveMax = UnicodeScalar.fromInt(maxCodePointValue + 1)\n        XCTAssertNil(\n            aboveMax,\n            \"UnicodeScalar.fromInt should return nil when above maximum value.\"\n        )\n        \n        let belowMin = UnicodeScalar.fromInt(-1)\n        XCTAssertNil(\n            belowMin,\n            \"UnicodeScalar.fromInt should return nil when below minimm value.\"\n        )\n        \n        let minSurrogatePair = UnicodeScalar.fromInt(minSurrogatePairValue)\n        XCTAssertNil(\n            minSurrogatePair,\n            \"UnicodeScalar.fromInt should return nil when a surrogate pair.\"\n        )\n        \n        let maxSurrogatePair = UnicodeScalar.fromInt(maxSurrogatePairValue)\n        XCTAssertNil(\n            maxSurrogatePair,\n            \"UnicodeScalar.fromInt should return nil when a surrogate pair.\"\n        )\n        \n    }\n    \n    func testFromUInt32() {\n        \n        // Test boundary conditions\n        \n        let aboveMax = UnicodeScalar.fromUInt32(UInt32(maxCodePointValue) + 1)\n        XCTAssertNil(\n            aboveMax,\n            \"UnicodeScalar.fromUInt32 should return nil when above maximum \" +\n                \"value.\"\n        )\n        \n        let minSurrogatePair = UnicodeScalar.fromUInt32(\n            UInt32(minSurrogatePairValue)\n        )\n        XCTAssertNil(\n            minSurrogatePair,\n            \"UnicodeScalar.fromUInt32 should return nil when a surrogate pair.\"\n        )\n        \n        let maxSurrogatePair = UnicodeScalar.fromUInt32(\n            UInt32(maxSurrogatePairValue)\n        )\n        XCTAssertNil(\n            maxSurrogatePair,\n            \"UnicodeScalar.fromUInt32 should return nil when a surrogate pair.\"\n        )\n        \n    }\n    \n}\n\nextension UnicodeScalarTests {\n    static var allTests: [(String, (UnicodeScalarTests) -> () throws -> Void)] {\n        return [\n            (\"testFromInt\", testFromInt),\n            (\"testFromUInt32\", testFromUInt32)\n        ]\n    }\n}\n"
  },
  {
    "path": "scripts/install-swift.sh",
    "content": "#!/bin/bash\n\nset -ev\n\nSWIFT_VERSION=\"3.0.2\"\nSWIFT_URL=\"https://swift.org/builds/swift-${SWIFT_VERSION}-release/ubuntu1404/swift-${SWIFT_VERSION}-RELEASE/swift-${SWIFT_VERSION}-RELEASE-ubuntu14.04.tar.gz\"\n\nif [ \"${TRAVIS_OS_NAME}\" = \"linux\" ]; then\n  mkdir .swift\n  curl -sSL \"${SWIFT_URL}\" | tar xz -C .swift &> /dev/null\n  export PATH=$(pwd)/.swift/swift-${SWIFT_VERSION}-RELEASE-ubuntu14.04/usr/bin:$PATH\nfi\n"
  },
  {
    "path": "scripts/run-tests.sh",
    "content": "#!/bin/bash\n\nset -ev\n\nif [ ! -z \"${XCODE_DESTINATION}\" ]; then\n  PARSEC=\"-project SwiftParsec.xcodeproj -scheme SwiftParsec\"\n  xcodebuild test $PARSEC -destination \"${XCODE_DESTINATION}\" TOOLCHAINS=swift\nelse\n  swift test\nfi\n"
  }
]