%{
  # -*- 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
  }

  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: fatalError("unknown token kind \(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
    }
  }
}
