// // repl.swift // REPL // // Created by Nick Lockwood on 02/03/2018. // Copyright © 2018 Nick Lockwood. All rights reserved. // import Foundation // MARK: API public final class State { fileprivate var variables = [String: Any]() } public func evaluate(_ input: String, state: State) throws -> Any? { let match = try command.match(input) return match.transform { label, values in switch label { case .bool: return values[0] as! String == "true" case .number: return Double(values[0] as! String) ?? 0 case .string: return values[0] as! String case .variable: return state.variables[values[0] as! String] ?? (nil as Any? as Any) case .factor: if values[0] as? String == "-" { guard let value = values[1] as? Double else { return Double.nan } return -value } return values[0] case .term, .expression: if values.count == 1 { return values[0] } let op = values[1] as! String guard let lhs = values[0] as? Double, let rhs = values[2] as? Double else { if op == "+", values[0] is String || values[2] is String { return "\(values[0])\(values[2])" } return Double.nan } switch op { case "+": return lhs + rhs case "-": return lhs - rhs case "*": return lhs * rhs case "/": return lhs / rhs default: preconditionFailure() } case .assignment: let lhs = values[0] as! String let rhs = values[1] state.variables[lhs] = rhs return rhs case .command: return values[0] } } } // MARK: Implementation private enum Label: String { case bool case number case string case variable case factor case term case expression case assignment case command } /// boolean private let bool: Consumer