<commit_before>//
//  JSONParser.swift
//  BNRSwiftJSON
//
//  Created by <NAME> on 4/18/15.
//  Copyright (c) 2015 BigNerdRanch. All rights reserved.
//

import Foundation
import Result

public func JSONFromString(s: String) -> Result<JSON> {
    return s.nulTerminatedUTF8.withUnsafeBufferPointer { nulTerminatedBuffer in
        // don't want to include the nul termination in the buffer - trim it off
        let buffer = UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress, count: nulTerminatedBuffer.count - 1)
        return JSONFromUnsafeBufferPointer(buffer)
    }
}

public func JSONFromUTF8Data(data: NSData) -> Result<JSON> {
    let buffer = UnsafeBufferPointer(start: UnsafePointer<UInt8>(data.bytes), count: data.length)
    return JSONFromUnsafeBufferPointer(buffer)
}

public func JSONFromUnsafeBufferPointer(buffer: UnsafeBufferPointer<UInt8>) -> Result<JSON> {
    var parser = Parser(input: buffer)
    switch parser.parse() {
    case .Ok(let json):
        return Result(success: json)
    case .Err(let error):
        return Result(failure: error)
    }
}

private func makeParseError(reason: String) -> Parser.Result {
    return .Err(JSON.makeError(.CouldNotParseJSON, problem: reason))
}

private struct Literal {
    static let BACKSLASH     = UInt8(ascii: "\\")
    static let BACKSPACE     = UInt8(ascii: "\u{0008}")
    static let COLON         = UInt8(ascii: ":")
    static let COMMA         = UInt8(ascii: ",")
    static let DOUBLE_QUOTE  = UInt8(ascii: "\"")
    static let FORMFEED      = UInt8(ascii: "\u{000c}")
    static let LEFT_BRACE    = UInt8(ascii: "{")
    static let LEFT_BRACKET  = UInt8(ascii: "[")
    static let MINUS         = UInt8(ascii: "-")
    static let NEWLINE       = UInt8(ascii: "\n")
    static let PERIOD        = UInt8(ascii: ".")
    static let PLUS          = UInt8(ascii: "+")
    static let RETURN        = UInt8(ascii: "\r")
    static let RIGHT_BRACE   = UInt8(ascii: "}")
    static let RIGHT_BRACKET = UInt8(ascii: "]")
    static let SLASH         = UInt8(ascii: "/")
    static let SPACE         = UInt8(ascii: " ")
    static let TAB           = UInt8(ascii: "\t")

    static let a = UInt8(ascii: "a")
    static let b = UInt8(ascii: "b")
    static let c = UInt8(ascii: "c")
    static let d = UInt8(ascii: "d")
    static let e = UInt8(ascii: "e")
    static let f = UInt8(ascii: "f")
    static let l = UInt8(ascii: "l")
    static let n = UInt8(ascii: "n")
    static let r = UInt8(ascii: "r")
    static let s = UInt8(ascii: "s")
    static let t = UInt8(ascii: "t")
    static let u = UInt8(ascii: "u")

    static let A = UInt8(ascii: "A")
    static let B = UInt8(ascii: "B")
    static let C = UInt8(ascii: "C")
    static let D = UInt8(ascii: "D")
    static let E = UInt8(ascii: "E")
    static let F = UInt8(ascii: "F")

    static let zero  = UInt8(ascii: "0")
    static let one   = UInt8(ascii: "1")
    static let two   = UInt8(ascii: "2")
    static let three = UInt8(ascii: "3")
    static let four  = UInt8(ascii: "4")
    static let five  = UInt8(ascii: "5")
    static let six   = UInt8(ascii: "6")
    static let seven = UInt8(ascii: "7")
    static let eight = UInt8(ascii: "8")
    static let nine  = UInt8(ascii: "9")
}

private struct Parser {
    enum Result {
        case Ok(JSON)
        case Err(NSError)
    }

    enum Sign: Double {
        case Positive = 1.0
        case Negative = -1.0
    }

    let input: UnsafeBufferPointer<UInt8>
    var loc = 0

    init(input: UnsafeBufferPointer<UInt8>) {
        self.input = input
    }

    mutating func parse() -> Result {
        switch parseValue() {
        case let .Ok(value):
            if loc != input.count {
                skipWhitespace()
                if loc != input.count {
                    return makeParseError("unexpected data after parsed JSON")
                }
            }
            return .Ok(value)

        case let result:
            return result
        }
    }

    mutating func parseValue() -> Result {
        while loc < input.count {
            switch input[loc] {
            case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
                ++loc

            case Literal.LEFT_BRACE:
                return decodeObject()

            case Literal.LEFT_BRACKET:
                return decodeArray()

            case Literal.DOUBLE_QUOTE:
                return decodeString()

            case Literal.MINUS:
                return decodeNumberNegative(loc)

            case Literal.zero:
                return decodeNumberLeadingZero(loc, sign: .Positive)

            case Literal.one...Literal.nine:
                return decodeNumberPreDecimalDigits(loc, sign: .Positive)

            case Literal.n:
                return decodeNull()

            case Literal.t:
                return decodeTrue()

            case Literal.f:
                return decodeFalse()

            default:
                return makeParseError("did not find start of valid JSON data")
            }
        }
        return makeParseError("did not find start of valid JSON data")
    }

    mutating func skipWhitespace() {
        while loc < input.count {
            switch input[loc] {
            case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
                ++loc

            default:
                return
            }
        }
    }<commit_msg>Reorders parsing cases for slight speed boost<commit_after>//
//  JSONParser.swift
//  BNRSwiftJSON
//
//  Created by <NAME> on 4/18/15.
//  Copyright (c) 2015 BigNerdRanch. All rights reserved.
//

import Foundation
import Result

public func JSONFromString(s: String) -> Result<JSON> {
    return s.nulTerminatedUTF8.withUnsafeBufferPointer { nulTerminatedBuffer in
        // don't want to include the nul termination in the buffer - trim it off
        let buffer = UnsafeBufferPointer(start: nulTerminatedBuffer.baseAddress, count: nulTerminatedBuffer.count - 1)
        return JSONFromUnsafeBufferPointer(buffer)
    }
}

public func JSONFromUTF8Data(data: NSData) -> Result<JSON> {
    let buffer = UnsafeBufferPointer(start: UnsafePointer<UInt8>(data.bytes), count: data.length)
    return JSONFromUnsafeBufferPointer(buffer)
}

public func JSONFromUnsafeBufferPointer(buffer: UnsafeBufferPointer<UInt8>) -> Result<JSON> {
    var parser = Parser(input: buffer)
    switch parser.parse() {
    case .Ok(let json):
        return Result(success: json)
    case .Err(let error):
        return Result(failure: error)
    }
}

private func makeParseError(reason: String) -> Parser.Result {
    return .Err(JSON.makeError(.CouldNotParseJSON, problem: reason))
}

private struct Literal {
    static let BACKSLASH     = UInt8(ascii: "\\")
    static let BACKSPACE     = UInt8(ascii: "\u{0008}")
    static let COLON         = UInt8(ascii: ":")
    static let COMMA         = UInt8(ascii: ",")
    static let DOUBLE_QUOTE  = UInt8(ascii: "\"")
    static let FORMFEED      = UInt8(ascii: "\u{000c}")
    static let LEFT_BRACE    = UInt8(ascii: "{")
    static let LEFT_BRACKET  = UInt8(ascii: "[")
    static let MINUS         = UInt8(ascii: "-")
    static let NEWLINE       = UInt8(ascii: "\n")
    static let PERIOD        = UInt8(ascii: ".")
    static let PLUS          = UInt8(ascii: "+")
    static let RETURN        = UInt8(ascii: "\r")
    static let RIGHT_BRACE   = UInt8(ascii: "}")
    static let RIGHT_BRACKET = UInt8(ascii: "]")
    static let SLASH         = UInt8(ascii: "/")
    static let SPACE         = UInt8(ascii: " ")
    static let TAB           = UInt8(ascii: "\t")

    static let a = UInt8(ascii: "a")
    static let b = UInt8(ascii: "b")
    static let c = UInt8(ascii: "c")
    static let d = UInt8(ascii: "d")
    static let e = UInt8(ascii: "e")
    static let f = UInt8(ascii: "f")
    static let l = UInt8(ascii: "l")
    static let n = UInt8(ascii: "n")
    static let r = UInt8(ascii: "r")
    static let s = UInt8(ascii: "s")
    static let t = UInt8(ascii: "t")
    static let u = UInt8(ascii: "u")

    static let A = UInt8(ascii: "A")
    static let B = UInt8(ascii: "B")
    static let C = UInt8(ascii: "C")
    static let D = UInt8(ascii: "D")
    static let E = UInt8(ascii: "E")
    static let F = UInt8(ascii: "F")

    static let zero  = UInt8(ascii: "0")
    static let one   = UInt8(ascii: "1")
    static let two   = UInt8(ascii: "2")
    static let three = UInt8(ascii: "3")
    static let four  = UInt8(ascii: "4")
    static let five  = UInt8(ascii: "5")
    static let six   = UInt8(ascii: "6")
    static let seven = UInt8(ascii: "7")
    static let eight = UInt8(ascii: "8")
    static let nine  = UInt8(ascii: "9")
}

private struct Parser {
    enum Result {
        case Ok(JSON)
        case Err(NSError)
    }

    enum Sign: Double {
        case Positive = 1.0
        case Negative = -1.0
    }

    let input: UnsafeBufferPointer<UInt8>
    var loc = 0

    init(input: UnsafeBufferPointer<UInt8>) {
        self.input = input
    }

    mutating func parse() -> Result {
        switch parseValue() {
        case let .Ok(value):
            if loc != input.count {
                skipWhitespace()
                if loc != input.count {
                    return makeParseError("unexpected data after parsed JSON")
                }
            }
            return .Ok(value)

        case let result:
            return result
        }
    }

    mutating func parseValue() -> Result {
        while loc < input.count {
            switch input[loc] {
            case Literal.LEFT_BRACKET:
                return decodeArray()

            case Literal.LEFT_BRACE:
                return decodeObject()

            case Literal.DOUBLE_QUOTE:
                return decodeString()

            case Literal.f:
                return decodeFalse()

            case Literal.n:
                return decodeNull()

            case Literal.t:
                return decodeTrue()

            case Literal.MINUS:
                return decodeNumberNegative(loc)

            case Literal.zero:
                return decodeNumberLeadingZero(loc, sign: .Positive)

            case Literal.one...Literal.nine:
                return decodeNumberPreDecimalDigits(loc, sign: .Positive)

            case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
                ++loc

            default:
                return makeParseError("did not find start of valid JSON data")
            }
        }
        
        return makeParseError("Invalid value around character \(loc)")
    }

    mutating func skipWhitespace() {
        while loc < input.count {
            switch input[loc] {
            case Literal.SPACE, Literal.TAB, Literal.RETURN, Literal.NEWLINE:
                ++loc

            default:
                return
            }
        }
    }
{'fraction_non_alphanumeric': 0.10982019363762102, 'fraction_numerical': 0.015491009681881052, 'mean_word_length': 2.0415030846887268, 'pattern_counts': {'":': 2, '<': 23, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6876489', 'n_tokens_mistral': 3568, 'n_tokens_neox': 3333, 'n_words': 927}