'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 |
|---|
