'How does Storing Failable Results for Later / trailing closure syntax to call Result(catching:) work in Swift?

Within chapter on error handling there is an example on expression evaluator and code on storing Failable Results for Later - code below, lines after implementation of function evaluate. This part does throw more errors, would like to ask if you can help to clarify these. I am going back from the beggining of the book again, checking sources and practicing more examples. Still appreciate your help, so when comming back can study it more.

enum Token: CustomStringConvertible {
    case number (Int)
    case plus
    
    var description: String {
        switch self {
        case .number (let n):
            return "Number: \(n)"
        case .plus:
            return "Symbol: +"
        }
    }
}

class Lexer {
    enum Error: Swift.Error {
        case invalidCharacter (Character)
    }
    
    let input: String
    var position: String.Index
    
    init(input: String) {
        self.input = input
        self.position = input.startIndex
    }
    
    func peek() -> Character? {
        guard position < input.endIndex else {
            return nil
        }
        return input[position]
    }
    
    func advance() {
        assert(position < input.endIndex, "Cannot advance past endIndex!")
        position = input.index(after: position)
    }
    
    func getNumber() -> Int {
        var value = 0
        
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0" ... "9":
                let digitValue = Int(String(nextCharacter))!
                value = 10*value + digitValue
                advance()
            default:
                return value
            }
        }
        return value
    }
    
    func lex() throws -> [Token] {
        var tokens = [Token]()
        
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0" ... "9":
                let value = getNumber()
                tokens.append(.number(value))
            case "+":
                tokens.append(.plus)
                advance()
            case " ":
                advance()
            default:
                throw Lexer.Error.invalidCharacter(nextCharacter)
            }
        }
        return tokens
    }
}

func evaluate(_ input: String) {
    print("Evaluating: \(input)")
    let lexer = Lexer(input: input)
    do {
        let tokens = try lexer.lex()
        print("Lexer output: \(tokens)")
    
        let parser = Parser(tokens: tokens)
        let result = try parser.parse()
        print("Parser output: \(result)")
    } catch Lexer.Error.invalidCharacter(let character) {
        print("Input contained an invalid character: \(character)")
    } catch Parser.Error.unexpectedEndOfInput {
        print("Unexpected end of input during parsing")
    } catch Parser.Error.invalidToken(let token) {
        print("Invalid token during parsing: \(token)")
    } catch {
        print("An error occured: \(error)")
    }
}

class Parser {
    enum Error: Swift.Error {
        case unexpectedEndOfInput
        case invalidToken(Token)
    }
    
    let tokens: [Token]
    var position = 0
    
    init(tokens: [Token]) {
        self.tokens = tokens
    }
    
    func getNextToken() -> Token? {
        guard position < tokens.count else {
            return nil
        }
        
        let token = tokens[position]
        position += 1
        return token
    }
    
    func getNumber() throws -> Int {
        guard let token = getNextToken() else {
            throw Parser.Error.unexpectedEndOfInput
        }
        
        switch token {
        case .number(let value):
            return value
        case .plus:
            throw Parser.Error.invalidToken(token)
        }
    }
    
    func parse() throws -> Int {
        var value = try getNumber()
        
        while let token = getNextToken() {
            switch token {
            case .plus:
                let nextNumber = try getNumber()
                value += nextNumber
            case .number:
                throw Parser.Error.invalidToken(token)
            }
        }
        return value
    }
}

evaluate("10 + 1")

// below is code on Storing Failable Results for Later:

let lexer = Lexer(input: "1 + 3 + 3 + 7")
let tokensResult = Result { try lexer.lex() } // Result<Success, Failure>' cannot be constructed because it has no accessible initializers

enum Result<Success, Failure> where Failure : Error {
        case .success(Success) // Extraneous '.' in enum 'case' declaration
        case .failure(Failure) // Extraneous '.' in enum 'case' declaration
    }

switch tokensResult {
case let .success(tokens):
    print("Found \(tokens.count) tokens \(tokens)")
case let .failure(error):
    print("Could not lex \(lexer.input): \(error)")
}

let numbersResult: Result<[Int],Error> = tokensResult.map {
      tokens.compactMap { token in // Cannot find 'tokens' in scope
          switch token {
          case let .number(digit): return digit
          default: return nil
          }
      }
}

func extractNumbers(from result: Result<[Int],Error>) throws -> [Int] {
        return try result.get() // Value of type 'Result<[Int], Error>' has no member 'get'
    }


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source