XCode shows errors in example code in Ch. 20


#1

I am getting errors when I type the Chapter 20 “Lexer” code into an XCode playground:

enum Error: ErrorType (XCode: “ErrorType has been renamed to Error”)

++position
Unary operator ‘++’ cannot be applied to an operand of type ‘@lvalue String.CharacterView.Index’ (aka ‘@lvalue String.Index’)

throw Error.InvalidCharacter(nextCharacter)
Thrown expression type ‘Lexer.Error’ does not conform to ‘Error’

Is the sample code in the book correct?

thanks.


#2

It is most likely that the sample code was written for an earlier version of the Swift. If that is the case, you need to port the sample code to the version of the Swift you are now using.

I don’t have the book, but if you post the sample code I may be able to help you.


#3

I haven’t posted code before so I’m not sure if I’m doing this right, but here it is. This is the Lexer from Chapter 20:

import Cocoa

enum Token {
case Number(Int)
case Plus
}

class Lexer {
enum Error: ErrorType {
case InvalidCharacter(Character)
}

let input: String.CharacterView
var position: String.CharacterView.Index

init(input: String) {
    self.input = input.characters
    self.position = self.input.startIndex
}

func peek() -> Character? {
    guard position < input.endIndex else {
        return nil
    }
    return input[position]
}
func advance() {
    assert(position < input.endIndex, "Cannot advance past the end!")
    ++position
}

func getNumber() -> Int{
        var value = 0
    
    while let nextCharacter = peek() {
        switch nextCharacter {
        case "0" ... "9":
            // Another digit - add it into value
            let digitValue = Int(String(nextCharacter))!
            value = 10*value + digitValue
            advance()
            
        default:
            // A non-digit - go back to regular lexing
            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 " ":
            // Just advance to ignore spaces
            advance()
            
        default:
            throw Error.InvalidCharacter(nextCharacter)
        }
    }
    
    return tokens
}

}

func evaluate(input: String) {
print(“Evaluating: (input)”)
let lexer = Lexer(input: input)
let tokens = lexer.lex()
print(“Lexer output: (tokens)”)
}

evaluate(“10 + 3 + 5”)
evaluate(“1 + 2 + abcdefg”)


And here are the errors I get in the window at the bottom of the XCode playground:

Playground execution failed:

error: ErrorHandling.playground:5:17: error: ‘ErrorType’ has been renamed to ‘Error’
enum Error: ErrorType {
^~~~~~~~~
Error

error: ErrorHandling.playground:5:10: error: type ‘Lexer.Error’ does not conform to protocol ‘RawRepresentable’
enum Error: ErrorType {
^

error: ErrorHandling.playground:82:10: error: missing argument label ‘input:’ in call
evaluate(“10 + 3 + 5”)
^
input:

error: ErrorHandling.playground:83:10: error: missing argument label ‘input:’ in call
evaluate(“1 + 2 + abcdefg”)
^
input:

error: ErrorHandling.playground:25:11: error: unary operator ‘++’ cannot be applied to an operand of type ‘@lvalue String.CharacterView.Index’ (aka ‘@lvalue String.Index’)
++position
^

ErrorHandling.playground:25:11: note: overloads for ‘++’ exist with these partially matching parameter lists: (inout Float), (inout Double), (inout Float80), (inout CGFloat)
++position
^

error: ErrorHandling.playground:67:29: error: thrown expression type ‘Lexer.Error’ does not conform to ‘Error’
throw Error.InvalidCharacter(nextCharacter)
^~~~~~~~~~~~~~~~~~~~~~~~~

error: ErrorHandling.playground:78:18: error: call can throw, but it is not marked with ‘try’ and the error is not handled
let tokens = lexer.lex()
^

If I made some typo somewhere and didn’t catch it, I apologize in advance.
ML


#4

Okay, here we go.

1.You can post your code pretty-formatted, by enclosing it between a pair of 3 back-tick characters ```.

For example, if you write this:
```
let PI = 4.0 * atan (1.0)
```

you will see this:

let PI = 4.0 * atan (1.0)

2.Compare the following code (written with Xcode Version 9.3 (9E145)) to yours and note the differences.

import Cocoa

enum Token {
    case Number(Int)
    case Plus
}

class Lexer {
    enum Error: Swift.Error {
        case InvalidCharacter (Character)
    }
    
    let input: String
    var position: String.Index
    
    init (input: String) {
        self.input = input
        self.position = self.input.startIndex
    }
    
    func peek() -> Character? {
        guard position < input.endIndex else {
            return nil
        }
        return input[position]
    }
    func advance() {
        assert (position < input.endIndex, "Cannot advance past the end!")
        position = input.index (after: position)
    }
    
    func getNumber() -> Int{
        var value = 0
        
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0" ... "9":
                // Another digit - add it into value
                let digitValue = Int(String(nextCharacter))!
                value = 10*value + digitValue
                advance()
                
            default:
                // A non-digit - go back to regular lexing
                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 " ":
                // Just advance to ignore spaces
                advance()
                
            default:
                throw 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)")
    }
    catch let x {
        print ("Lexer error: \(x)")
    }
}

evaluate ("10 + 3 + 5")
evaluate ("1 + 2 + abcdefg")

If you need more help with coding, you can find me at Pretty Function.


#5

Thank you very much for your help.
ML