Skip to content

Commit

Permalink
Fixed parsing bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
Obbut committed Mar 20, 2017
1 parent 4c6c2fc commit 6edd6ba
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 24 deletions.
2 changes: 1 addition & 1 deletion Sources/Array.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public struct JSONArray: Value, InitializableSequence, ExpressibleByArrayLiteral

/// Initializes this JSON Array with a JSON String containing this array in JSON format
public init(from data: String, allowingComments: Bool = true) throws {
var parser = JSON(data.makeJSONBinary(), allowingComments: allowingComments)
var parser = JSON(data.utf8, allowingComments: allowingComments)
self = try parser.parse(rootLevel: true)
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Object.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public struct JSONObject : Value, InitializableObject, ExpressibleByDictionaryLi

/// Initializes this Object from a JSON String
public init(from data: String, allowingComments: Bool = true) throws {
var parser = JSON(data.makeJSONBinary(), allowingComments: allowingComments)
var parser = JSON(data.utf8, allowingComments: allowingComments)
self = try parser.parse(rootLevel: true)
}

Expand Down
38 changes: 21 additions & 17 deletions Sources/Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ public struct JSON {
var position: Int = 0

/// Initializes this JSON context
internal init(_ data: [UInt8], allowingComments: Bool) {
self.data = data
internal init<S : Sequence>(_ data: S, allowingComments: Bool) where S.Iterator.Element == UInt8 {
self.data = Array(data)
}

/// Parses an escaped unicode character (as hexadecimal) at the current position
Expand Down Expand Up @@ -136,7 +136,7 @@ public struct JSON {

position += 1

var characters = ""
var characters = [UInt8]()

loop: while position < data.count {
if data[position] == SpecialCharacters.escape {
Expand All @@ -150,28 +150,28 @@ public struct JSON {
case 0x75:
position += 1
let unicodeScalar = try parseUnicode()
characters.append(Character(unicodeScalar))
characters.append(contentsOf: String(unicodeScalar).utf8)
case SpecialCharacters.stringQuotationMark:
characters.append(SpecialCharacters.stringQuotationMark.character)
characters.append(SpecialCharacters.stringQuotationMark)
position += 1
case SpecialCharacters.escape:
characters.append(SpecialCharacters.escape.character)
characters.append(SpecialCharacters.escape)
position += 1
case 0x2f: // `/`
characters.append(SpecialCharacters.slash.character)
characters.append(SpecialCharacters.slash)
position += 1
case 0x62: // `b`
throw JSONError.unsupported
case 0x66: // `f`
throw JSONError.unsupported
case 0x6e: // `n`
characters.append(SpecialCharacters.lineFeed.character)
characters.append(SpecialCharacters.lineFeed)
position += 1
case 0x72: // `r`
characters.append(SpecialCharacters.carriageReturn.character)
characters.append(SpecialCharacters.carriageReturn)
position += 1
case 0x74: // `t`
characters.append(SpecialCharacters.tab.character)
characters.append(SpecialCharacters.tab)
position += 1
default:
throw JSONError.invalidEscapedCharacter
Expand All @@ -182,9 +182,13 @@ public struct JSON {

try skipWhitespace()

return characters
guard let string = String(bytes: characters, encoding: .utf8) else {
throw JSONError.invalidString
}

return string
} else {
characters.append(data[position].character)
characters.append(data[position])
position += 1
}
}
Expand Down Expand Up @@ -535,11 +539,11 @@ public struct JSON {

/// Parses any value given a String
public static func parse(from data: String, allowingComments: Bool = true) throws -> Value {
return try parse(from: data.makeJSONBinary())
return try parse(from: data.utf8)
}

/// Parses any value given a String bytes buffer
public static func parse(from data: [UInt8], allowingComments: Bool = true) throws -> Value {
public static func parse<S : Sequence>(from data: S, allowingComments: Bool = true) throws -> Value where S.Iterator.Element == UInt8 {
var parser = JSON(data, allowingComments: allowingComments)
try parser.skipWhitespace()

Expand All @@ -559,23 +563,23 @@ public struct JSON {
case 0x30...0x39, SpecialCharacters.minus:
result = try parser.parseNumber()
case 0x6e: // `n`
guard parser.remaining(4), [UInt8](data[parser.position..<parser.position + 4]) == SpecialWords.null else {
guard parser.remaining(4), [UInt8](parser.data[parser.position..<parser.position + 4]) == SpecialWords.null else {
throw JSONError.unknownValue
}

parser.position += 4

result = Null()
case 0x74: // `t`
guard parser.remaining(4), [UInt8](data[parser.position..<parser.position + 4]) == SpecialWords.true else {
guard parser.remaining(4), [UInt8](parser.data[parser.position..<parser.position + 4]) == SpecialWords.true else {
throw JSONError.unknownValue
}

parser.position += 4

result = true
case 0x66: // `f`
guard parser.remaining(5), [UInt8](data[parser.position..<parser.position + 5]) == SpecialWords.false else {
guard parser.remaining(5), [UInt8](parser.data[parser.position..<parser.position + 5]) == SpecialWords.false else {
throw JSONError.unknownValue
}

Expand Down
3 changes: 3 additions & 0 deletions Sources/Value.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ public enum JSONError : Error {
/// -
case invalidObject

/// -
case invalidString

/// -
case invalidArray

Expand Down
10 changes: 5 additions & 5 deletions Tests/CheetahTests/ParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ParsingTests: XCTestCase {
// MARK: - Null

func testNullParses() throws {
XCTAssert(try JSON.parse(from: "null") is Null)
XCTAssert(try JSON.parse(from: "null") is NSNull)
}

func testNullThrowsOnMismatch() {
Expand Down Expand Up @@ -60,7 +60,7 @@ class ParsingTests: XCTestCase {
func testArray_JustNull() throws {
let array = try JSONArray(from: "[ null ]")

XCTAssertEqual(array, [Null()])
XCTAssertEqual(array, [NSNull()])
}

func testArray_ZeroBegining() throws {
Expand All @@ -77,12 +77,12 @@ class ParsingTests: XCTestCase {

func testArray_NullsBoolsNums_Normal_Minimal_RootParser() throws {
XCTAssertEqual(try JSONArray(from: "[null,true,false,12,-10,-24.3,18.2e9]"),
[Null(), true, false, 12, -10, -24.3, 18200000000.0])
[NSNull(), true, false, 12, -10, -24.3, 18200000000.0])
}

func testArray_NullsBoolsNums_Normal_MuchWhitespace() throws {
XCTAssertEqual(try JSONArray(from: " \t[\n null ,true, \n-12.3 , false\r\n]\n "),
[Null(), true, -12.3, false])
[NSNull(), true, -12.3, false])
}

func testArray_NullsAndBooleans_Bad_MissingEnd() {
Expand Down Expand Up @@ -428,7 +428,7 @@ class ParsingTests: XCTestCase {
parse("{\t'hello': 'wor🇨🇿ld', \n\t 'val': 1234, 'many': [\n-12.32, null, 'yo'\r], 'emptyDict': {}, 'dict': {'arr':[]}, 'name': true}", to: [
"hello": "wor🇨🇿ld",
"val": 1234,
"many": [-12.32, Null(), "yo"] as JSONArray,
"many": [-12.32, NSNull(), "yo"] as JSONArray,
"emptyDict": [:] as JSONObject,
"dict": ["arr": [] as JSONArray] as JSONObject,
"name": true
Expand Down

0 comments on commit 6edd6ba

Please sign in to comment.