text: // Copyright 2020 The Tint Authors.
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  #ifndef SRC_READER_WGSL_TOKEN_H_
  #define SRC_READER_WGSL_TOKEN_H_
  
  #include <string>
  
  #include "src/source.h"
  
  namespace tint {
  namespace reader {
  namespace wgsl {
  
  /// Stores tokens generated by the Lexer
  class Token {
   public:
    /// The type of the parsed token
    enum class Type {
      /// Error result
      kError = -2,
      /// Uninitialized token
      kUninitialized = 0,
      /// End of input string reached
      kEOF,
  
      /// An identifier
      kIdentifier,
      /// A float value
      kFloatLiteral,
      /// An signed int value
      kSintLiteral,
      /// A unsigned int value
      kUintLiteral,
  
      /// A '&'
      kAnd,
      /// A '&&'
      kAndAnd,
      /// A '->'
      kArrow,
      /// A '[['
      kAttrLeft,
      /// A ']]'
      kAttrRight,
      /// A '/'
      kForwardSlash,
      /// A '!'
      kBang,
      /// A '['
      kBracketLeft,
      /// A ']'
      kBracketRight,
      /// A '{'
      kBraceLeft,
      /// A '}'
      kBraceRight,
      /// A ':'
      kColon,
      /// A ','
      kComma,
      /// A '='
      kEqual,
      /// A '=='
      kEqualEqual,
      /// A '>'
      kGreaterThan,
      /// A '>='
      kGreaterThanEqual,
      /// A '>>'
      kShiftRight,
      /// A '<'
      kLessThan,
      /// A '<='
      kLessThanEqual,
      /// A '<<'
      kShiftLeft,
      /// A '%'
      kMod,
      /// A '-'
      kMinus,
      /// A '--'
      kMinusMinus,
      /// A '!='
      kNotEqual,
      /// A '.'
      kPeriod,
      /// A '+'
      kPlus,
      /// A '++'
      kPlusPlus,
      /// A '|'
      kOr,
      /// A '||'
      kOrOr,
      /// A '('
      kParenLeft,
      /// A ')'
      kParenRight,
      /// A ';'
      kSemicolon,
      /// A '*'
      kStar,
      /// A '~'
      kTilde,
      /// A '_'
      kUnderscore,
      /// A '^'
      kXor,
  
      /// A 'array'
      kArray,
      /// A 'atomic'
      kAtomic,
      /// A 'bitcast'
      kBitcast,
      /// A 'bool'
      kBool,
      /// A 'break'
      kBreak,
      /// A 'case'
      kCase,
      /// A 'continue'
      kContinue,
      /// A 'continuing'
      kContinuing,
      /// A 'discard'
      kDiscard,
      /// A 'default'
      kDefault,
      /// A 'else'
      kElse,
      /// A 'elseif'
      kElseIf,
      /// A 'f32'
      kF32,
      /// A 'fallthrough'
      kFallthrough,
      /// A 'false'
      kFalse,
      /// A 'fn'
      kFn,
      // A 'for'
      kFor,
      // A 'Bgra8Unorm' format
      kFormatBgra8Unorm,
      // A 'Bgra8UnormSrgb' format
      kFormatBgra8UnormSrgb,
      // A 'R16Float' format
      kFormatR16Float,
      // A 'R16Sint' format
      kFormatR16Sint,
      // A 'R16Uint' format
      kFormatR16Uint,
      // A 'R32Float' format
      kFormatR32Float,
      // A 'R32Sint' format
      kFormatR32Sint,
      // A 'R32Uint' format
      kFormatR32Uint,
      // A 'R8Sint' format
      kFormatR8Sint,
      // A 'R8Snorm' format
      kFormatR8Snorm,
      // A 'R8Uint' format
      kFormatR8Uint,
      // A 'R8Unorm' format
      kFormatR8Unorm,
      // A 'Rg11B10Float' format
      kFormatRg11B10Float,
      // A 'Rg16Float' format
      kFormatRg16Float,
      // A 'Rg16Sint' format
      kFormatRg16Sint,
      // A 'Rg16Uint' format
      kFormatRg16Uint,
      // A 'Rg32Float' format
      kFormatRg32Float,
      // A 'Rg32Sint' format
      kFormatRg32Sint,
      // A 'Rg32Uint' format
      kFormatRg32Uint,
      // A 'Rg8Sint' format
      kFormatRg8Sint,
      // A 'Rg8Snorm' format
      kFormatRg8Snorm,
      // A 'Rg8Uint' format
      kFormatRg8Uint,
      // A 'Rg8Unorm' format
      kFormatRg8Unorm,
      // A 'Rgb10A2Unorm' format
      kFormatRgb10A2Unorm,
      // A 'Rgba16Float' format
      kFormatRgba16Float,
      // A 'Rgba16Sint' format
      kFormatRgba16Sint,
      // A 'Rgba16Uint' format
      kFormatRgba16Uint,
      // A 'Rgba32Float' format
      kFormatRgba32Float,
      // A 'Rgba32Sint' format
      kFormatRgba32Sint,
      // A 'Rgba32Uint' format
      kFormatRgba32Uint,
      // A 'Rgba8Sint' format
      kFormatRgba8Sint,
      // A 'Rgba8Snorm' format
      kFormatRgba8Snorm,
      // A 'Rgba8Uint' format
      kFormatRgba8Uint,
      // A 'Rgba8Unorm' format
      kFormatRgba8Unorm,
      // A 'Rgba8UnormSrgb' format
      kFormatRgba8UnormSrgb,
      /// A 'function'
      kFunction,
      /// A 'i32'
      kI32,
      /// A 'if'
      kIf,
      /// A 'image'
      kImage,
      /// A 'import'
      kImport,
      /// A 'let'
      kLet,
      /// A 'loop'
      kLoop,
      /// A 'mat2x2'
      kMat2x2,
      /// A 'mat2x3'
      kMat2x3,
      /// A 'mat2x4'
      kMat2x4,
      /// A 'mat3x2'
      kMat3x2,
      /// A 'mat3x3'
      kMat3x3,
      /// A 'mat3x4'
      kMat3x4,
      /// A 'mat4x2'
      kMat4x2,
      /// A 'mat4x3'
      kMat4x3,
      /// A 'mat4x4'
      kMat4x4,
      /// A 'private'
      kPrivate,
      /// A 'ptr'
      kPtr,
      /// A 'return'
      kReturn,
      /// A 'sampler'
      kSampler,
      /// A 'sampler_comparison'
      kComparisonSampler,
      /// A 'storage'
      kStorage,
      /// A 'struct'
      kStruct,
      /// A 'switch'
      kSwitch,
      /// A 'texture_depth_2d'
      kTextureDepth2d,
      /// A 'texture_depth_2d_array'
      kTextureDepth2dArray,
      /// A 'texture_depth_cube'
      kTextureDepthCube,
      /// A 'texture_depth_cube_array'
      kTextureDepthCubeArray,
      /// A 'texture_depth_multisampled_2d'
      kTextureDepthMultisampled2d,
      /// A 'texture_external'
      kTextureExternal,
      /// A 'texture_multisampled_2d'
      kTextureMultisampled2d,
      /// A 'texture_1d'
      kTextureSampled1d,
      /// A 'texture_2d'
      kTextureSampled2d,
      /// A 'texture_2d_array'
      kTextureSampled2dArray,
      /// A 'texture_3d'
      kTextureSampled3d,
      /// A 'texture_cube'
      kTextureSampledCube,
      /// A 'texture_cube_array'
      kTextureSampledCubeArray,
      /// A 'texture_storage_1d'
      kTextureStorage1d,
      /// A 'texture_storage_2d'
      kTextureStorage2d,
      /// A 'texture_storage_2d_array'
      kTextureStorage2dArray,
      /// A 'texture_storage_3d'
      kTextureStorage3d,
      /// A 'true'
      kTrue,
      /// A 'type'
      kType,
      /// A 'u32'
      kU32,
      /// A 'uniform'
      kUniform,
      /// A 'var'
      kVar,
      /// A 'vec2'
      kVec2,
      /// A 'vec3'
      kVec3,
      /// A 'vec4'
      kVec4,
      /// A 'workgroup'
      kWorkgroup,
    };
  
    /// Converts a token type to a name
    /// @param type the type to convert
    /// @returns the token type as as string
    static std::string TypeToName(Type type);
  
    /// Creates an uninitialized token
    Token();
    /// Create a Token
    /// @param type the Token::Type of the token
    /// @param source the source of the token
    Token(Type type, const Source& source);
  
    /// Create a string Token
    /// @param type the Token::Type of the token
    /// @param source the source of the token
    /// @param val the source string for the token
    Token(Type type, const Source& source, const std::string& val);
    /// Create a unsigned integer Token
    /// @param source the source of the token
    /// @param val the source unsigned for the token
    Token(const Source& source, uint32_t val);
    /// Create a signed integer Token
    /// @param source the source of the token
    /// @param val the source integer for the token
    Token(const Source& source, int32_t val);
    /// Create a float Token
    /// @param source the source of the token
    /// @param val the source float for the token
    Token(const Source& source, float val);
    /// Move constructor
    Token(Token&&);
    /// Copy constructor
    Token(const Token&);
    ~Token();
  
    /// Assignment operator
    /// @param b the token to copy
    /// @return Token
    Token& operator=(const Token& b);
  
    /// Returns true if the token is of the given type
    /// @param t the type to check against.
    /// @returns true if the token is of type `t`
    bool Is(Type t) const { return type_ == t; }
  
    /// @returns true if the token is uninitialized
    bool IsUninitialized() const { return type_ == Type::kUninitialized; }
    /// @returns true if the token is EOF
    bool IsEof() const { return type_ == Type::kEOF; }
    /// @returns true if the token is Error
    bool IsError() const { return type_ == Type::kError; }
    /// @returns true if the token is an identifier
    bool IsIdentifier() const { return type_ == Type::kIdentifier; }
    /// @returns true if the token is a literal
    bool IsLiteral() const {
      return type_ == Type::kSintLiteral || type_ == Type::kFalse ||
             type_ == Type::kUintLiteral || type_ == Type::kTrue ||
             type_ == Type::kFloatLiteral;
    }
    /// @returns true if token is a 'matNxM'
    bool IsMatrix() const {
      return type_ == Type::kMat2x2 || type_ == Type::kMat2x3 ||
             type_ == Type::kMat2x4 || type_ == Type::kMat3x2 ||
             type_ == Type::kMat3x3 || type_ == Type::kMat3x4 ||
             type_ == Type::kMat4x2 || type_ == Type::kMat4x3 ||
             type_ == Type::kMat4x4;
    }
    /// @returns true if token is a 'mat3xM'
    bool IsMat3xN() const {
      return type_ == Type::kMat3x2 || type_ == Type::kMat3x3 ||
             type_ == Type::kMat3x4;
    }
    /// @returns true if token is a 'mat4xM'
    bool IsMat4xN() const {
      return type_ == Type::kMat4x2 || type_ == Type::kMat4x3 ||
             type_ == Type::kMat4x4;
    }
    /// @returns true if token is a 'matNx3'
    bool IsMatNx3() const {
      return type_ == Type::kMat2x3 || type_ == Type::kMat3x3 ||
             type_ == Type::kMat4x3;
    }
    /// @returns true if token is a 'matNx4'
    bool IsMatNx4() const {
      return type_ == Type::kMat2x4 || type_ == Type::kMat3x4 ||
             type_ == Type::kMat4x4;
    }
  
    /// @returns true if token is a 'vecN'
    bool IsVector() const {
      return type_ == Type::kVec2 || type_ == Type::kVec3 || type_ == Type::kVec4;
    }
  
    /// @returns the source information for this token
    Source source() const { return source_; }
  
    /// Returns the string value of the token
    /// @return const std::string&
    std::string to_str() const;
    /// Returns the float value of the token. 0 is returned if the token does not
    /// contain a float value.
    /// @return float
    float to_f32() const;
    /// Returns the uint32 value of the token. 0 is returned if the token does not
    /// contain a unsigned integer value.
    /// @return uint32_t
    uint32_t to_u32() const;
    /// Returns the int32 value of the token. 0 is returned if the token does not
    /// contain a signed integer value.
    /// @return int32_t
    int32_t to_i32() const;
  
    /// @returns the token type as string
    std::string to_name() const { return Token::TypeToName(type_); }
  
   private:
    /// The Token::Type of the token
    Type type_ = Type::kError;
    /// The source where the token appeared
    Source source_;
    /// The string represented by the token
    std::string val_str_;
    /// The signed integer represented by the token
    int32_t val_int_ = 0;
    /// The unsigned integer represented by the token
    uint32_t val_uint_ = 0;
    /// The float value represented by the token
    float val_float_ = 0.0;
  };
  
  #ifndef NDEBUG
  inline std::ostream& operator<<(std::ostream& out, Token::Type type) {
    out << Token::TypeToName(type);
    return out;
  }
  #endif  // NDEBUG
  
  }  // namespace wgsl
  }  // namespace reader
  }  // namespace tint
  
  #endif  // SRC_READER_WGSL_TOKEN_H_
  