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