|
7 | 7 |
|
8 | 8 | extension URLTemplate {
|
9 | 9 | internal static func scan(
|
10 |
| - _ string: String, |
11 |
| - partialToken: PartialToken?, |
12 |
| - from remainder: Substring, |
13 |
| - addingTo tokens: [Component] |
| 10 | + _ string: String |
14 | 11 | ) throws -> [Component] {
|
15 |
| - guard let next = remainder.first else { |
16 |
| - guard partialToken == nil || partialToken?.type == .constant else { |
17 |
| - throw ParsingError.unterminatedVariable(name: String(partialToken?.string ?? "")) |
18 |
| - } |
19 |
| - return tokens + tokenArray(from: partialToken) |
20 |
| - } |
21 |
| - let nextFirstIndex = remainder.index(remainder.startIndex, offsetBy: 1, limitedBy: remainder.endIndex) |
| 12 | + var tokens = [Component]() |
| 13 | + var remainder = string[...] |
| 14 | + var partialToken: PartialToken? = nil |
| 15 | + |
| 16 | + while let next = remainder.first { |
| 17 | + let nextFirstIndex = remainder.index(remainder.startIndex, offsetBy: 1, limitedBy: remainder.endIndex) |
22 | 18 |
|
23 |
| - switch (partialToken?.type, next) { |
24 |
| - case (nil, "{"), |
25 |
| - (.constant, "{"): |
26 |
| - guard let newFirstIndex = nextFirstIndex else { |
27 |
| - throw ParsingError.unterminatedVariable(name: "") |
28 |
| - } |
29 |
| - let newTokens = tokens + tokenArray(from: partialToken) |
30 |
| - return try scan( |
31 |
| - string, |
32 |
| - partialToken: .init(type: .variable, string: remainder[newFirstIndex..<newFirstIndex]), |
33 |
| - from: remainder.dropFirst(), |
34 |
| - addingTo: newTokens |
35 |
| - ) |
| 19 | + switch (partialToken?.type, next) { |
| 20 | + case (nil, "{"), |
| 21 | + (.constant, "{"): |
| 22 | + guard let newFirstIndex = nextFirstIndex else { |
| 23 | + throw ParsingError.unterminatedVariable(name: "") |
| 24 | + } |
| 25 | + tokens += tokenArray(from: partialToken) |
| 26 | + partialToken = .init(type: .variable, string: remainder[newFirstIndex..<newFirstIndex]) |
| 27 | + remainder = remainder.dropFirst() |
36 | 28 |
|
37 |
| - case (.variable, "}"): |
38 |
| - let newTokens = tokens + tokenArray(from: partialToken) |
39 |
| - return try scan(string, partialToken: nil, from: remainder.dropFirst(), addingTo: newTokens) |
| 29 | + case (.variable, "}"): |
| 30 | + tokens += tokenArray(from: partialToken) |
| 31 | + partialToken = nil |
| 32 | + remainder = remainder.dropFirst() |
40 | 33 |
|
41 |
| - case (nil, "}"), |
42 |
| - (.constant, "}"): |
43 |
| - throw ParsingError.variableEndedWithoutStarting(name: partialToken.map { String($0.string) } ?? "") |
| 34 | + case (nil, "}"), |
| 35 | + (.constant, "}"): |
| 36 | + throw ParsingError.variableEndedWithoutStarting(name: partialToken.map { String($0.string) } ?? "") |
44 | 37 |
|
45 |
| - case (.variable, "{"): |
46 |
| - throw ParsingError.variableStartedWithinVariable(name: partialToken.map { String($0.string) } ?? "") |
| 38 | + case (.variable, "{"): |
| 39 | + throw ParsingError.variableStartedWithinVariable(name: partialToken.map { String($0.string) } ?? "") |
47 | 40 |
|
48 |
| - case (nil, _): |
49 |
| - return try scan( |
50 |
| - string, |
51 |
| - partialToken: .init(type: .constant, string: remainder[remainder.startIndex...remainder.startIndex]), |
52 |
| - from: remainder.dropFirst(), |
53 |
| - addingTo: tokens |
54 |
| - ) |
| 41 | + case (nil, _): |
| 42 | + partialToken = .init(type: .constant, string: remainder[remainder.startIndex...remainder.startIndex]) |
| 43 | + remainder = remainder.dropFirst() |
55 | 44 |
|
56 |
| - case (.constant, _), |
57 |
| - (.variable, _): |
58 |
| - guard nextFirstIndex != nil, let reifiedPartialToken = partialToken else { |
59 |
| - return tokens + tokenArray(from: partialToken) |
| 45 | + case (.constant, _), |
| 46 | + (.variable, _): |
| 47 | + guard nextFirstIndex != nil, let reifiedPartialToken = partialToken else { |
| 48 | + tokens += tokenArray(from: partialToken) |
| 49 | + continue |
| 50 | + } |
| 51 | + partialToken = reifiedPartialToken.advancingStringByOne(within: string) |
| 52 | + remainder = remainder.dropFirst() |
60 | 53 | }
|
61 |
| - return try scan( |
62 |
| - string, |
63 |
| - partialToken: reifiedPartialToken.advancingStringByOne(within: string), |
64 |
| - from: remainder.dropFirst(), |
65 |
| - addingTo: tokens |
66 |
| - ) |
67 | 54 | }
|
| 55 | + guard partialToken == nil || partialToken?.type == .constant else { |
| 56 | + throw ParsingError.unterminatedVariable(name: String(partialToken?.string ?? "")) |
| 57 | + } |
| 58 | + return tokens + tokenArray(from: partialToken) |
68 | 59 | }
|
69 | 60 |
|
70 | 61 | internal static func tokenArray(from partial: PartialToken?) -> [Component] {
|
|
0 commit comments