Gold Challenge (a different approach)


#1

import Cocoa
import Foundation

enum Token {
case Number(Int)
case Plus
case Minus
case Multiplied // my add for the Gold Challenge
case Divided // my add for the Gold Challenge

func associatedValue() -> Int? {    // my add for the Gold Challenge
    switch self {
    case .Number(let value):
        return value
    default:
        return nil
    }
}

}

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 = position.successor()
}

func lex() throws -> [Token] {
    var tokens = [Token]()
    
    while let nextCharacter = peek() {
        switch nextCharacter {
        case "0" ... "9":
            let value = getNumber()
            tokens.append(.Number(value))
        case "*":    // my add for the Gold Challenge
            tokens.append(.Multiplied)
            advance()
        case "/":   // my add for the Gold Challenge
            tokens.append(.Divided)
            advance()
        case "+":
            tokens.append(.Plus)
            advance()
        case "-":
            tokens.append(.Minus)
            advance()
        case " ":
            advance()
        default:
            throw Error.invalidCharacter(nextCharacter)
        }
    }
    return tokens
}

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 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)
    parser.multAndDiv()
    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: ErrorType {
    case UnexpectedEndOfInput
    case InvalidToken(Token)
}

var tokens: [Token]   // my modification for the Gold Challenge (var instead of let)
var position = 0
var posizione = 0    // my add for the Gold Challenge

init(tokens: [Token]) {
    self.tokens = tokens
}

func getNextToken() -> Token? {
    guard position < tokens.count else {
        return nil
    }
    return tokens[position++]
}

func getNumber() throws -> Int {
    guard let token = getNextToken() else {
        throw Error.UnexpectedEndOfInput
    }
    switch token {
    case .Number(let value):
        return value
    case .Plus:
        throw Error.InvalidToken(token)
    case .Minus:
        throw Error.InvalidToken(token)
    case .Multiplied:   // my add for the Gold Challenge
        throw Error.InvalidToken(token)
    case .Divided:    // my add for the Gold Challenge
        throw Error.InvalidToken(token)
    }
}

func parse() throws -> Int {
    
    var value = try getNumber()
    
    while let token = getNextToken() {
        switch token {
        case .Multiplied:  // my add for the Gold Challenge
            break
        case .Divided:  // my add for the Gold Challenge
            break
        case .Plus:
            let nextNumber = try getNumber()
            value += nextNumber
        case .Minus:
            let nextNumber = try getNumber()
            value -= nextNumber
        case .Number:
            throw Error.InvalidToken(token)
        }
    }
    return value
}

func multAndDiv()  {   // my add for the Gold Challenge
    for token in tokens {
        switch token {
        case .Multiplied:
            let firstTerm: Int = tokens[posizione - 1].associatedValue()!
            let secondTerm: Int = tokens[posizione + 1].associatedValue()!
            let resultTerm: Int = firstTerm * secondTerm
            for _ in 0...2 {
                tokens.removeAtIndex(posizione - 1)
            }
            tokens.insert(.Number(resultTerm), atIndex: posizione - 1)
            posizione = posizione - 2
        case .Divided:
            let firstTerm: Int = tokens[posizione - 1].associatedValue()!
            let secondTerm: Int = tokens[posizione + 1].associatedValue()!
            let resultTerm: Int = firstTerm / secondTerm
            for _ in 0...2 {
                tokens.removeAtIndex(posizione - 1)
            }
            tokens.insert(.Number(resultTerm), atIndex: posizione - 1)
            posizione = posizione - 2
        default:
            break
        }
        print(tokens)
        posizione += 1
    }
}

}