Skip to content

Commit

Permalink
Use parseFromLookupTable()
Browse files Browse the repository at this point in the history
  • Loading branch information
danieleggert committed Dec 30, 2024
1 parent de98f3c commit 2dd0091
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 91 deletions.
151 changes: 83 additions & 68 deletions Sources/NIOIMAPCore/Parser/Grammar/GrammarParser+Mailbox.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,66 +35,97 @@ extension GrammarParser {
// "STATUS" SP mailbox SP "(" [status-att-list] ")" /
// number SP "EXISTS" / Namespace-Response
func parseMailboxData(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
func parseMailboxData_flags(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseFixedString("FLAGS ", buffer: &buffer, tracker: tracker)
return .flags(try self.parseFlagList(buffer: &buffer, tracker: tracker))
}
/// Parse those sub-parses that have a fixed text prefix.
func parseMailboxData_withFixedPrefix(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
func parseMailboxData_flags(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
return .flags(try self.parseFlagList(buffer: &buffer, tracker: tracker))
}

func parseMailboxData_list(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseFixedString("LIST ", buffer: &buffer, tracker: tracker)
return .list(try self.parseMailboxList(buffer: &buffer, tracker: tracker))
}
func parseMailboxData_list(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
return .list(try self.parseMailboxList(buffer: &buffer, tracker: tracker))
}

func parseMailboxData_lsub(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseFixedString("LSUB ", buffer: &buffer, tracker: tracker)
return .lsub(try self.parseMailboxList(buffer: &buffer, tracker: tracker))
}
func parseMailboxData_lsub(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
return .lsub(try self.parseMailboxList(buffer: &buffer, tracker: tracker))
}

func parseMailboxData_extendedSearch(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
let response = try self.parseExtendedSearchResponse(buffer: &buffer, tracker: tracker)
return .extendedSearch(response)
}
func parseMailboxData_extendedSearch(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
let response = try self.parseExtendedSearchResponse(buffer: &buffer, tracker: tracker)
return .extendedSearch(response)
}

func parseMailboxData_search(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseFixedString("SEARCH", buffer: &buffer, tracker: tracker)
let nums = try PL.parseZeroOrMore(buffer: &buffer, tracker: tracker) {
(buffer, tracker) -> UnknownMessageIdentifier in
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
let num = try self.parseNZNumber(buffer: &buffer, tracker: tracker)
guard let id = UnknownMessageIdentifier(exactly: num) else {
throw ParserError(hint: "Can't make unknown message identfiier from \(num)")

func parseMailboxData_search_combined(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
func parseMailboxData_search(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
let nums = try PL.parseZeroOrMore(buffer: &buffer, tracker: tracker) {
(buffer, tracker) -> UnknownMessageIdentifier in
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
let num = try self.parseNZNumber(buffer: &buffer, tracker: tracker)
guard let id = UnknownMessageIdentifier(exactly: num) else {
throw ParserError(hint: "Can't make unknown message identfiier from \(num)")
}
return id
}
return .search(nums)
}
return id
}
return .search(nums)
}

func parseMailboxData_searchSort(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseFixedString("SEARCH", buffer: &buffer, tracker: tracker)
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
var array = [try self.parseNZNumber(buffer: &buffer, tracker: tracker)]
try PL.parseZeroOrMore(
buffer: &buffer,
into: &array,
tracker: tracker,
parser: { (buffer, tracker) in
func parseMailboxData_searchSort(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
return try self.parseNZNumber(buffer: &buffer, tracker: tracker)
var array = [try self.parseNZNumber(buffer: &buffer, tracker: tracker)]
try PL.parseZeroOrMore(
buffer: &buffer,
into: &array,
tracker: tracker,
parser: { (buffer, tracker) in
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
return try self.parseNZNumber(buffer: &buffer, tracker: tracker)
}
)
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
let seq = try self.parseSearchSortModificationSequence(buffer: &buffer, tracker: tracker)
return .searchSort(.init(identifiers: array, modificationSequence: seq))
}
)
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
let seq = try self.parseSearchSortModificationSequence(buffer: &buffer, tracker: tracker)
return .searchSort(.init(identifiers: array, modificationSequence: seq))
}

func parseMailboxData_status(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseFixedString("STATUS ", buffer: &buffer, tracker: tracker)
let mailbox = try self.parseMailbox(buffer: &buffer, tracker: tracker)
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
try PL.parseFixedString("(", buffer: &buffer, tracker: tracker)
let status = try PL.parseOptional(buffer: &buffer, tracker: tracker, parser: self.parseMailboxStatus)
try PL.parseFixedString(")", buffer: &buffer, tracker: tracker)
return .status(mailbox, status ?? .init())
return try PL.parseOneOf(
parseMailboxData_searchSort,
parseMailboxData_search,
buffer: &buffer,
tracker: tracker
)
}

func parseMailboxData_status(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
let mailbox = try self.parseMailbox(buffer: &buffer, tracker: tracker)
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
try PL.parseFixedString("(", buffer: &buffer, tracker: tracker)
let status = try PL.parseOptional(buffer: &buffer, tracker: tracker, parser: self.parseMailboxStatus)
try PL.parseFixedString(")", buffer: &buffer, tracker: tracker)
return .status(mailbox, status ?? .init())
}

func parseMailboxData_namespace(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
.namespace(try self.parseNamespaceResponse(buffer: &buffer, tracker: tracker))
}

func parseMailboxData_uidBatchesResponse(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
.uidBatches(try self.parseUIDBatchesResponse(buffer: &buffer, tracker: tracker))
}

let commandParsers: [String: (inout ParseBuffer, StackTracker) throws -> MailboxData] = [
"FLAGS": parseMailboxData_flags,
"LIST": parseMailboxData_list,
"LSUB": parseMailboxData_lsub,
"ESEARCH": parseMailboxData_extendedSearch,
"SEARCH": parseMailboxData_search_combined,
"STATUS": parseMailboxData_status,
"NAMESPACE": parseMailboxData_namespace,
"UIDBATCHES": parseMailboxData_uidBatchesResponse,
]
return try parseFromLookupTable(buffer: &buffer, tracker: tracker, parsers: commandParsers)
}

func parseMailboxData_exists(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
Expand All @@ -109,27 +140,11 @@ extension GrammarParser {
return .recent(number)
}

func parseMailboxData_namespace(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
.namespace(try self.parseNamespaceResponse(buffer: &buffer, tracker: tracker))
}

func parseMailboxData_uidBatchesResponse(buffer: inout ParseBuffer, tracker: StackTracker) throws -> MailboxData {
.uidBatches(try self.parseUIDBatchesResponse(buffer: &buffer, tracker: tracker))
}

return try PL.parseOneOf(
[
parseMailboxData_flags,
parseMailboxData_list,
parseMailboxData_lsub,
parseMailboxData_extendedSearch,
parseMailboxData_status,
parseMailboxData_withFixedPrefix,
parseMailboxData_exists,
parseMailboxData_recent,
parseMailboxData_searchSort,
parseMailboxData_search,
parseMailboxData_namespace,
parseMailboxData_uidBatchesResponse,
],
buffer: &buffer,
tracker: tracker
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ extension GrammarParser {
}

func parseSuffix_namespace(buffer: inout ParseBuffer, tracker: StackTracker) throws -> ResponseTextCode {
.namespace(try self.parseNamespaceSuffix(buffer: &buffer, tracker: tracker))
.namespace(try self.parseNamespaceResponse(buffer: &buffer, tracker: tracker))
}

func parseResponseTextCode_atom(buffer: inout ParseBuffer, tracker: StackTracker) throws -> ResponseTextCode {
Expand Down
15 changes: 3 additions & 12 deletions Sources/NIOIMAPCore/Parser/Grammar/GrammarParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,6 @@ extension GrammarParser {
func parseExtendedSearchResponse(buffer: inout ParseBuffer, tracker: StackTracker) throws -> ExtendedSearchResponse
{
try PL.composite(buffer: &buffer, tracker: tracker) { (buffer, tracker) in
try PL.parseFixedString("ESEARCH", buffer: &buffer, tracker: tracker)
let correlator = try PL.parseOptional(buffer: &buffer, tracker: tracker, parser: self.parseSearchCorrelator)
let kind: ExtendedSearchResponse.Kind =
try PL.parseOptional(buffer: &buffer, tracker: tracker) { (buffer, tracker) in
Expand Down Expand Up @@ -1821,17 +1820,8 @@ extension GrammarParser {
}
}

// Namespace-Response = "*" SP "NAMESPACE" SP Namespace
// SP Namespace SP Namespace
func parseNamespaceResponse(buffer: inout ParseBuffer, tracker: StackTracker) throws -> NamespaceResponse {
try PL.composite(buffer: &buffer, tracker: tracker) { buffer, tracker -> NamespaceResponse in
try PL.parseFixedString("NAMESPACE", buffer: &buffer, tracker: tracker)
return try parseNamespaceSuffix(buffer: &buffer, tracker: tracker)
}
}

// SP Namespace SP Namespace SP Namespace
func parseNamespaceSuffix(buffer: inout ParseBuffer, tracker: StackTracker) throws -> NamespaceResponse {
func parseNamespaceResponse(buffer: inout ParseBuffer, tracker: StackTracker) throws -> NamespaceResponse {
try PL.composite(buffer: &buffer, tracker: tracker) { buffer, tracker -> NamespaceResponse in
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
let n1 = try self.parseNamespace(buffer: &buffer, tracker: tracker)
Expand All @@ -1847,7 +1837,8 @@ extension GrammarParser {
// [SP uid-range *("," uid-range) ]
func parseUIDBatchesResponse(buffer: inout ParseBuffer, tracker: StackTracker) throws -> UIDBatchesResponse {
try PL.composite(buffer: &buffer, tracker: tracker) { buffer, tracker -> UIDBatchesResponse in
try PL.parseFixedString(#"UIDBATCHES (TAG ""#, buffer: &buffer, tracker: tracker)
try PL.parseSpaces(buffer: &buffer, tracker: tracker)
try PL.parseFixedString(#"(TAG ""#, buffer: &buffer, tracker: tracker)
let tag = try self.parseTag(buffer: &buffer, tracker: tracker)
try PL.parseFixedString("\")", buffer: &buffer, tracker: tracker)
let batches = try PL.parseOptional(buffer: &buffer, tracker: tracker) { buffer, tracker -> [UIDRange] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ extension GrammarParser_Mailbox_Tests {
.extendedSearch(.init(correlator: nil, kind: .sequenceNumber, returnData: [.min(1), .max(2)])),
#line
),
("ESEARCH", "\r", .extendedSearch(.init(correlator: nil, kind: .sequenceNumber, returnData: [])), #line),
("1234 EXISTS", "\r\n", .exists(1234), #line),
("5678 RECENT", "\r\n", .recent(5678), #line),
("STATUS INBOX ()", "\r\n", .status(.inbox, .init()), #line),
Expand Down
20 changes: 10 additions & 10 deletions Tests/NIOIMAPCoreTests/Parser/IMAPParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1455,18 +1455,18 @@ extension ParserUnitTests {
self.iterateTests(
testFunction: GrammarParser().parseExtendedSearchResponse,
validInputs: [
("ESEARCH", "\r", .init(correlator: nil, kind: .sequenceNumber, returnData: []), #line),
("ESEARCH UID", "\r", .init(correlator: nil, kind: .uid, returnData: []), #line),
("", "\r", .init(correlator: nil, kind: .sequenceNumber, returnData: []), #line),
(" UID", "\r", .init(correlator: nil, kind: .uid, returnData: []), #line),
(
"ESEARCH (TAG \"col\") UID", "\r",
" (TAG \"col\") UID", "\r",
.init(correlator: SearchCorrelator(tag: "col"), kind: .uid, returnData: []), #line
),
(
"ESEARCH (TAG \"col\") UID COUNT 2", "\r",
" (TAG \"col\") UID COUNT 2", "\r",
.init(correlator: SearchCorrelator(tag: "col"), kind: .uid, returnData: [.count(2)]), #line
),
(
"ESEARCH (TAG \"col\") UID MIN 1 MAX 2", "\r",
" (TAG \"col\") UID MIN 1 MAX 2", "\r",
.init(correlator: SearchCorrelator(tag: "col"), kind: .uid, returnData: [.min(1), .max(2)]), #line
),
],
Expand All @@ -1483,12 +1483,12 @@ extension ParserUnitTests {
self.iterateTests(
testFunction: GrammarParser().parseUIDBatchesResponse,
validInputs: [
(#"UIDBATCHES (TAG "A143") 215295:99695,99696:20350,20351:7829,7830:1"#, "\r", .init(correlator: "A143", batches: [
(#" (TAG "A143") 215295:99695,99696:20350,20351:7829,7830:1"#, "\r", .init(correlator: "A143", batches: [
99695...215295, 20350...99696, 7829...20351, 1...7830,
]), #line),
(#"UIDBATCHES (TAG "A143")"#, "\r", .init(correlator: "A143", batches: []), #line),
(#"UIDBATCHES (TAG "A143") 99695"#, "\r", .init(correlator: "A143", batches: [99695...99695]), #line),
(#"UIDBATCHES (TAG "A143") 20350:20350"#, "\r", .init(correlator: "A143", batches: [20350...20350]), #line),
(#" (TAG "A143")"#, "\r", .init(correlator: "A143", batches: []), #line),
(#" (TAG "A143") 99695"#, "\r", .init(correlator: "A143", batches: [99695...99695]), #line),
(#" (TAG "A143") 20350:20350"#, "\r", .init(correlator: "A143", batches: [20350...20350]), #line),
],
parserErrorInputs: [],
incompleteMessageInputs: []
Expand Down Expand Up @@ -2318,7 +2318,7 @@ extension ParserUnitTests {
testFunction: GrammarParser().parseNamespaceResponse,
validInputs: [
(
"NAMESPACE nil nil nil", " ", .init(userNamespace: [], otherUserNamespace: [], sharedNamespace: []),
" nil nil nil", " ", .init(userNamespace: [], otherUserNamespace: [], sharedNamespace: []),
#line
)
],
Expand Down

0 comments on commit 2dd0091

Please sign in to comment.