在词法分析器中使用 Swift RegexBuilder - 将 ChoiceOf 匹配输出元组折叠为 (SubString, TypeOfMatch) 类型

Using Swift RegexBuilder in a lexer - collapsing ChoiceOf match output tuple to (SubString, TypeOfMatch) type

提问人:Philip Pegden 提问时间:10/6/2023 更新时间:10/6/2023 访问量:25

问:

我正在使用 Swift 的词法分析器阶段实现一个解析器。我想知道我的正则表达式语句是否可以改进。RegexBuilderChoiceOf

具体来说,在下面的示例代码中,当匹配时,它会生成一个类型的元组,其中成员的数量将等于构造中的正则表达式项的数量。假设块返回类型中的所有正则表达式项,是否仍然有表示它,以便返回类型为 。tokenRegex(SubString, Token?, Token?, ...)Token?ChoiceOfChoiceOfToken(SubString, Token?)

目前,我通过使用镜像功能折叠匹配输出元组来处理此问题,但如果可能的话,我想跳过这一步:

let token = Mirror(reflecting: match.output).children.compactMap({ $0.value as? Token }).first

下面是完整的示例代码。

import Foundation
import RegexBuilder

enum Token {
    case number(Double)
    case text(String)
    case error(String)
    
    static let tokenRegex = Regex {
        ChoiceOf {
            numberRegex
            textRegex
            // Further regex patterns, all returning type Token...
        }
    }
    
    static let numberRegex = Regex {
        Capture {
            .localizedDouble(locale: Locale(identifier: "en-US"))
        } transform: {
            Token.number($0)
    }}
    
    static let textRegex = Regex {
        Capture {
            OneOrMore(.word)
        } transform: {
            Token.text(String($0))
    }}
    
    static func tokenise(_ text: String) -> [Token] {
        var stringToParse = text
        var tokens: [Token] = []
        
        while !stringToParse.isEmpty {
            let (token, matchEndIndex) = findNextToken(in: stringToParse)
            tokens.append(token)
            stringToParse = String(stringToParse[matchEndIndex...])
        }
        return tokens
    }
    
    static func findNextToken(in string: String) -> (Token, String.Index) {
        do {
            return if
                let match = try tokenRegex.firstMatch(in: string),
                let token = Mirror(reflecting: match.output).children.compactMap({ $0.value as? Token }).first
            {
                (token, match.0.endIndex)
            } else {
                (.error("Parse error"), string.endIndex)
            }
        } catch {
            return (.error(error.localizedDescription), string.endIndex)
        }
    }
}

Token.tokenise("123MyDogIsHappy") // Produces -> [Token.double(123.0), Token.text("MyDogIsHappy")]

swift tokenize lexer swift-regexbuilder

评论


答: 暂无答案