Skip to content

Commit 7d7902c

Browse files
committed
[JSON] Style and documentation improvements, and cleanups
Update for review comments
1 parent 5ab0c7e commit 7d7902c

File tree

4 files changed

+170
-127
lines changed

4 files changed

+170
-127
lines changed

Sources/SwiftCompilerPlugin/CompilerPlugin.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@ extension CompilerPlugin {
195195
}
196196

197197
internal struct PluginHostConnection: MessageConnection {
198+
// File descriptor for input from the host.
198199
fileprivate let inputStream: CInt
200+
// File descriptor for output to the host.
199201
fileprivate let outputStream: CInt
200202

201203
func sendMessage<TX: Encodable>(_ message: TX) throws {
@@ -238,21 +240,22 @@ private func _write(_ fd: CInt, contentsOf buffer: UnsafeRawBufferPointer) throw
238240
let endPtr = ptr.advanced(by: buffer.count)
239241
while ptr != endPtr {
240242
switch write(fd, ptr, numericCast(endPtr - ptr)) {
241-
case -1: throw IOError.writeFailed(_ss_errno())
242-
case 0: throw IOError.writeFailed(0) /* unreachable */
243+
case -1: throw IOError.writeFailed(errno: _ss_errno())
244+
case 0: throw IOError.writeFailed(errno: 0) /* unreachable */
243245
case let n: ptr += Int(n)
244246
}
245247
}
246248
}
247249

248-
/// Fill the buffer to the file descriptor. Throws an error on failure.
249-
/// If the file descriptor reached the end-of-file, throws IOError.readReachedEndOfInput
250+
/// Fill the buffer from the file descriptor. Throws an error on failure.
251+
/// If the file descriptor reached the end-of-file before filling up the entire
252+
/// buffer, throws IOError.readReachedEndOfInput
250253
private func _read(_ fd: CInt, into buffer: UnsafeMutableRawBufferPointer) throws {
251254
guard var ptr = buffer.baseAddress else { return }
252255
let endPtr = ptr.advanced(by: buffer.count)
253256
while ptr != endPtr {
254257
switch read(fd, ptr, numericCast(endPtr - ptr)) {
255-
case -1: throw IOError.readFailed(_ss_errno())
258+
case -1: throw IOError.readFailed(errno: _ss_errno())
256259
case 0: throw IOError.readReachedEndOfInput
257260
case let n: ptr += Int(n)
258261
}
@@ -261,8 +264,8 @@ private func _read(_ fd: CInt, into buffer: UnsafeMutableRawBufferPointer) throw
261264

262265
private enum IOError: Error, CustomStringConvertible {
263266
case readReachedEndOfInput
264-
case readFailed(CInt)
265-
case writeFailed(CInt)
267+
case readFailed(errno: CInt)
268+
case writeFailed(errno: CInt)
266269

267270
var description: String {
268271
switch self {

Sources/SwiftCompilerPluginMessageHandling/JSON/JSONDecoding.swift

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ func decodeFromJSON<T: Decodable>(json: UnsafeBufferPointer<UInt8>) throws -> T
9595
private struct JSONMap {
9696
enum Descriptor: Int {
9797

98-
// MARK: - Keywords; size:1 [desc]
98+
// MARK: - Keywords; mapSize:1 [desc]
99+
// desc: Descriptor.rawValue
99100

100101
/// 'null'
101102
case nullKeyword
@@ -104,7 +105,10 @@ private struct JSONMap {
104105
/// 'false' size:1
105106
case falseKeyword
106107

107-
// MARK: - Scalar values; size:3 [desc, pointer, length]
108+
// MARK: - Scalar values; mapSize:3 [desc, pointer, length]
109+
// desc: Descriptor.rawValue
110+
// pointer: pointer to the start of the value in the source UTF-8 JSON buffer.
111+
// length: the length of the value in the source UTF-8 JSON buffer.
108112

109113
/// Integer and floating number.
110114
case number
@@ -115,7 +119,10 @@ private struct JSONMap {
115119
/// String with escape sequences.
116120
case string
117121

118-
// MARK: - Collections; size: 2 + variable [desc, size, element...]
122+
// MARK: - Collections; mapSize: 2 + variable [desc, size, element...]
123+
// desc: Descriptor.rawValue
124+
// size: the map size this collection occupies.
125+
// element * n: JSON values in this collection. For collections, sequence of key/value pairs.
119126

120127
/// Object '{ ... }'. Elements are (key, value)...
121128
case object
@@ -140,18 +147,22 @@ private struct JSONMapBuilder {
140147
mapData.reserveCapacity(128) // 128 is good enough for most PluginMessage.
141148
}
142149

150+
/// Record .nullKeyword, .trueKeyword, or .falseKeyword.
143151
@inline(__always)
144152
mutating func record(_ descriptor: JSONMap.Descriptor) {
145153
mapData.append(descriptor.rawValue)
146154
}
147155

156+
/// Record literal values i.e. numbers and strings, with a range in the source buffer.
148157
@inline(__always)
149158
mutating func record(_ descriptor: JSONMap.Descriptor, range: Range<UnsafePointer<UInt8>>) {
150159
mapData.append(descriptor.rawValue)
151160
mapData.append(Int(bitPattern: range.lowerBound))
152161
mapData.append(range.count)
153162
}
154163

164+
/// Record starting of a collection i.e. .array or .object. Must be paired with
165+
/// closeCollection(handle:) call using the returned handle.
155166
@inline(__always)
156167
mutating func startCollection(_ descriptor: JSONMap.Descriptor) -> Int {
157168
let handle = mapData.count
@@ -160,6 +171,7 @@ private struct JSONMapBuilder {
160171
return handle
161172
}
162173

174+
/// Close the collection. Accepts a "handle" returned from startCollection(_:).
163175
@inline(__always)
164176
mutating func closeCollection(handle: Int) {
165177
// 'handle': descriptor index.
@@ -172,7 +184,7 @@ private struct JSONMapBuilder {
172184
}
173185
}
174186

175-
enum JSONError: Error, CustomDebugStringConvertible {
187+
private enum JSONError: Error, CustomDebugStringConvertible {
176188
case unexpectedEndOfFile
177189
case unexpectedCharacter(UInt8, context: String)
178190

@@ -245,7 +257,7 @@ private struct JSONScanner {
245257
}
246258

247259
@inline(__always)
248-
mutating func expect(_ char: UnicodeScalar) throws {
260+
mutating func expect(ascii char: UnicodeScalar) throws {
249261
guard hasData else {
250262
throw JSONError.unexpectedEndOfFile
251263
}
@@ -256,30 +268,30 @@ private struct JSONScanner {
256268
}
257269

258270
mutating func scanNull() throws {
259-
try expect("u")
260-
try expect("l")
261-
try expect("l")
271+
try expect(ascii: "u")
272+
try expect(ascii: "l")
273+
try expect(ascii: "l")
262274
map.record(.nullKeyword)
263275
}
264276

265277
mutating func scanTrue() throws {
266-
try expect("r")
267-
try expect("u")
268-
try expect("e")
278+
try expect(ascii: "r")
279+
try expect(ascii: "u")
280+
try expect(ascii: "e")
269281
map.record(.trueKeyword)
270282
}
271283

272284
mutating func scanFalse() throws {
273-
try expect("a")
274-
try expect("l")
275-
try expect("s")
276-
try expect("e")
285+
try expect(ascii: "a")
286+
try expect(ascii: "l")
287+
try expect(ascii: "s")
288+
try expect(ascii: "e")
277289
map.record(.falseKeyword)
278290
}
279291

280292
mutating func scanString(start: Cursor) throws {
281293
ptr = start
282-
try expect("\"")
294+
try expect(ascii: "\"")
283295

284296
var hasEscape = false
285297
var hasNonASCII = false
@@ -288,13 +300,16 @@ private struct JSONScanner {
288300
// FIXME: Error for invalid UTF8 sequences.
289301
if ptr.pointee == UInt8(ascii: "\\") {
290302
hasEscape = true
303+
// eat '\'. Rest of the escape sequence are all ASCII. We just skip them
304+
// ignoring how many bytes are actually for the escape sequence. For
305+
// decoding, they are revisited in _JSONStingDecoder.decodeStringWithEscapes()
291306
_ = try advance()
292307
} else if ptr.pointee >= 0x80 {
293308
hasNonASCII = true
294309
}
295310
_ = try advance()
296311
}
297-
try expect("\"")
312+
try expect(ascii: "\"")
298313

299314
let kind: JSONMap.Descriptor
300315
if hasEscape {
@@ -308,6 +323,7 @@ private struct JSONScanner {
308323
}
309324

310325
mutating func scanNumber(start: Cursor) throws {
326+
// FIXME: Error for invalid literal e.g. 'e-', '.e+'
311327
ptr = start
312328
_ = advance(if: "-")
313329
while advance(if: "0"..."9") {}
@@ -328,15 +344,15 @@ private struct JSONScanner {
328344
while hasData {
329345
try scanString(start: ptr)
330346
skipWhitespace()
331-
try expect(":")
347+
try expect(ascii: ":")
332348
try scanValue()
333349
if advance(if: ",") {
334350
skipWhitespace()
335351
continue
336352
}
337353
break
338354
}
339-
try expect("}")
355+
try expect(ascii: "}")
340356
}
341357
map.closeCollection(handle: handle)
342358
}
@@ -353,7 +369,7 @@ private struct JSONScanner {
353369
}
354370
break
355371
}
356-
try expect("]")
372+
try expect(ascii: "]")
357373
}
358374
map.closeCollection(handle: handle)
359375
}
@@ -459,8 +475,8 @@ private enum _JSONStringParser {
459475

460476
/// Decode a string value that includes escape sequences.
461477
static func decodeStringWithEscapes(source: UnsafeBufferPointer<UInt8>) -> String? {
462-
// JSON string with escape sequences must be 2 bytes or longer.
463-
assert(source.count > 0)
478+
// JSON string with escape sequences must be== 0 2 bytes or longer.
479+
assert(!source.isEmpty)
464480

465481
// Decode 'source' UTF-8 JSON string literal into the uninitialized
466482
// UTF-8 buffer. Upon error, return 0 and make an empty string.
@@ -511,8 +527,8 @@ private enum _JSONStringParser {
511527
/// sequence, and call 'processCodeUnit' with the decoded value.
512528
/// Returns 'true' on error.
513529
///
514-
/// NOTE: We don't report detailed errors for now because we only care
515-
/// well-formed payloads from the compiler.
530+
/// - Note: We don't report detailed errors for now because we only care
531+
/// well-formed payloads from the compiler.
516532
private static func decodeEscapeSequence(
517533
cursor: inout UnsafePointer<UInt8>,
518534
end: UnsafePointer<UInt8>,
@@ -608,9 +624,9 @@ private enum _JSONNumberParser {
608624
static func parseFloatingPoint<Floating: BinaryFloatingPoint>(source: UnsafeBufferPointer<UInt8>) -> Floating? {
609625
var endPtr: UnsafeMutablePointer<CChar>? = nil
610626
let value: Floating?
611-
if (Floating.self == Double.self) {
627+
if Floating.self == Double.self {
612628
value = Floating(exactly: strtod(source.baseAddress!, &endPtr))
613-
} else if (Floating.self == Float.self) {
629+
} else if Floating.self == Float.self {
614630
value = Floating(exactly: strtof(source.baseAddress!, &endPtr))
615631
} else {
616632
fatalError("unsupported floating point type")
@@ -674,7 +690,8 @@ extension JSONMapValue {
674690
/// Returns true if this value represents a string and equals to 'str'.
675691
///
676692
/// This is faster than 'value.asString() == str' because this doesn't
677-
/// instantiate 'Swift.String' unless there are escaped characters.
693+
/// instantiate 'Swift.String' unless there are escaped characters or
694+
/// non-ASCII characters.
678695
func equals(to str: String) -> Bool {
679696
if self.is(.asciiSimpleString) {
680697
let lhs = valueBuffer()
@@ -794,7 +811,7 @@ private struct JSONDecoding {
794811
// MARK: Pure decoding functions.
795812
extension JSONDecoding {
796813
@inline(__always)
797-
static func _checkNotNull<T>(
814+
private static func _checkNotNull<T>(
798815
_ value: JSONMapValue,
799816
expectedType: T.Type,
800817
for codingPathNode: _CodingPathNode,
@@ -830,6 +847,7 @@ extension JSONDecoding {
830847
)
831848
)
832849
}
850+
833851
@inline(__always)
834852
static func _decode(
835853
_ value: JSONMapValue,
@@ -839,6 +857,7 @@ extension JSONDecoding {
839857
) throws -> Bool {
840858
try _unwrapOrThrow(value.asBool(), decoding: value, codingPathNode: codingPathNode, additionalKey)
841859
}
860+
842861
@inline(__always)
843862
static func _decode(
844863
_ value: JSONMapValue,
@@ -848,6 +867,7 @@ extension JSONDecoding {
848867
) throws -> String {
849868
try _unwrapOrThrow(value.asString(), decoding: value, codingPathNode: codingPathNode, additionalKey)
850869
}
870+
851871
@inline(__always)
852872
static func _decode<Integer: FixedWidthInteger>(
853873
_ value: JSONMapValue,
@@ -857,6 +877,7 @@ extension JSONDecoding {
857877
) throws -> Integer {
858878
try _unwrapOrThrow(value.asInteger(type), decoding: value, codingPathNode: codingPathNode, additionalKey)
859879
}
880+
860881
@inline(__always)
861882
static func _decode<Floating: BinaryFloatingPoint>(
862883
_ value: JSONMapValue,

0 commit comments

Comments
 (0)