%{
  # -*- mode: Swift -*-
  from gyb_syntax_support import *
  # Ignore the following admonition it applies to the resulting .swift file only
}%
//// Automatically Generated From TokenKind.swift.gyb.
//// Do Not Edit Directly!
//===----------------- TokenKind.swift - Token Kind Enum ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

/// Enumerates the kinds of tokens in the Swift language.
public enum TokenKind: Codable {
  case unknown
  case eof
% for token in SYNTAX_TOKENS:
%   kind = token.swift_kind()
%
%   # Tokens that don't have a set text have an associated value that
%   # contains their text.
%   if not token.text:
%     kind += '(String)'
%   end
  case ${kind}
% end

  /// The textual representation of this token kind.
  var text: String {
    switch self {
    case .unknown: return "unknown"
    case .eof: return ""
% for token in SYNTAX_TOKENS:
%   if token.text:
    case .${token.swift_kind()}: return "${token.text}"
%   else:
    case .${token.swift_kind()}(let text): return text
%   end
% end
    }
  }

  /// Keys for serializing and deserializing token kinds.
  enum CodingKeys: String, CodingKey {
    case kind, text
  }

  enum DecodeError: Error {
    case unknownTokenKind(String)
  }

  public init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    let kind = try container.decode(String.self, forKey: .kind)
    switch kind {
    case "unknown": self = .unknown
    case "eof": self = .eof
% for token in SYNTAX_TOKENS:
    case "${token.kind}":
%   if token.text:
      self = .${token.swift_kind()}
%   else:
      let text = try container.decode(String.self, forKey: .text)
      self = .${token.swift_kind()}(text)
%   end
% end
    default: throw DecodeError.unknownTokenKind(kind)
    }
  }

  public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(kind, forKey: .kind)
    try container.encode(text, forKey: .text)
  }
  
  var kind: String {
    switch self {
    case .unknown: return "unknown"
    case .eof: return "eof"
% for token in SYNTAX_TOKENS:
%   kind = token.swift_kind()
%   if not token.text:
%     kind += '(_)'
%   end
    case .${kind}: return "${token.kind}"
% end
    }
  }
}

extension TokenKind: Equatable {
  public static func ==(lhs: TokenKind, rhs: TokenKind) -> Bool {
    switch (lhs, rhs) {
    case (.unknown, .unknown): return true
    case (.eof, .eof): return true
% for token in SYNTAX_TOKENS:
%   kind = token.swift_kind()
%   if token.text:
    case (.${kind}, .${kind}): return true
%   else:
    case (.${kind}(let lhsText), .${kind}(let rhsText)):
      return lhsText == rhsText
%   end
% end
    default: return false
    }
  }
}
