text: // Copyright 2017-2020 The Verible 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 VERIBLE_COMMON_FORMATTING_FORMAT_TOKEN_H_
  #define VERIBLE_COMMON_FORMATTING_FORMAT_TOKEN_H_
  
  #include <algorithm>
  #include <iosfwd>
  #include <string>
  
  #include "absl/strings/string_view.h"
  #include "common/text/concrete_syntax_leaf.h"
  #include "common/text/token_info.h"
  
  namespace verible {
  
  // Enumeration for options for formatting spaces between tokens.
  // This controls what to explore (if not pre-determined).
  // Related enum: SpacingDecision
  enum class SpacingOptions {
    Undecided,   // unconstrained, not yet decided, to be optimized (default)
    MustAppend,  // cannot break here
    MustWrap,    // must break here
    Preserve,    // do not optimize, use original spacing
  };
  
  std::ostream& operator<<(std::ostream&, SpacingOptions);
  
  // Tri-state value that encodes how this token affects group balancing
  // for line-wrapping purposes.
  enum class GroupBalancing {
    None,  // This token does not involve any grouping.
    Open,  // This token marks the beginning of a balanced group.
    Close  // This token marks the closing of a balanced group.
           // TODO(fangism): Reset?  (separator)
  };
  
  std::ostream& operator<<(std::ostream&, GroupBalancing);
  
  // InterTokenInfo defines parameters that are important to formatting
  // decisions related to adjacent tokens.
  // This is used during wrapping exploration and optimization.
  // See also InterTokenDecision for decision-bound information.
  struct InterTokenInfo {
    // The number of spaces that should be inserted before this token.
    // This can be nonzero when a style guide dictates a mimimum spacing
    // between certain tokens.  This can be used to indent the first token
    // on a formatted line.
    // This *must* be nonzero when removing a space between tokens would
    // result in changing the lexical stream (incorrect).
    int spaces_required = 0;
  
    // The penalty for line-breaking before this token.
    // This value is used during optimization.
    int break_penalty = 0;
  
    // Encodes spacing exploration options.
    SpacingOptions break_decision = SpacingOptions::Undecided;
  
    // Point to previous position in string buffer before series of white space
    // tokens, for the sake of preserving space.
    // Together with the current token, they can form a string_view representing
    // pre-existing space from the original buffer.
    const char* preserved_space_start = nullptr;
  
    InterTokenInfo() = default;
    InterTokenInfo(const InterTokenInfo&) = default;
  
    // Comparison is only really used for testing.
    bool operator==(const InterTokenInfo& r) const {
      return spaces_required == r.spaces_required &&
             break_penalty == r.break_penalty &&
             break_decision == r.break_decision &&
             preserved_space_start == r.preserved_space_start;
    }
  
    bool operator!=(const InterTokenInfo& r) const { return !((*this) == r); }
  };
  
  // Human-readable form, for debugging.
  std::ostream& operator<<(std::ostream&, const InterTokenInfo&);
  
  // PreFormatToken is a wrapper for TokenInfo objects. It contains an original
  // pointer to a TokenInfo object, as well as additional information for
  // formatting purposes.  It is first used to markup an UnwrappedLine with
  // inter-token annotations.
  struct PreFormatToken {
    // The token this PreFormatToken holds. TokenInfo must outlive this object.
    const TokenInfo* token = nullptr;
  
    // The enum for this PreFormatToken, an abstraction from the TokenInfo enum
    // for decision making. The values are intended to come from language-specific
    // enumerations.
    int format_token_enum = -1;
  
    // Formatting parameters that apply between the previous token and this one.
    // This is used in annotating tokens before spacing/wrapping optimization.
    InterTokenInfo before;
  
    // This marks how this token is involved in group balancing for line-wrapping.
    GroupBalancing balancing = GroupBalancing::None;
  
    PreFormatToken() = default;
  
    explicit PreFormatToken(const TokenInfo* t) : token(t) {}
  
    explicit PreFormatToken(const verible::SyntaxTreeLeaf& leaf)
        : PreFormatToken(&leaf.get()) {}
  
    // The length of characters in the PreFormatToken
    int Length() const { return token->text.length(); }
  
    // Returns the text of the TokenInfo token held by this PreFormatToken
    absl::string_view Text() const { return token->text; }
  
    // Returns the enum of the TokenInfo token held by this PreFormatToken
    int TokenEnum() const { return token->token_enum; }
  
    // Reconstructs the original spacing that preceded this token.
    absl::string_view OriginalLeadingSpaces() const;
  
    // Returns a human-readable string representation of the FormatToken.
    // This is only intended for debugging.
    std::string ToString() const;
  };
  
  std::ostream& operator<<(std::ostream& stream, const PreFormatToken& token);
  
  // Enumeration for the final decision about spacing between tokens.
  // Related enum: SpacingConstraint.
  // These values are also used during line wrap searching and optimization.
  // Notably and intentionally, there is no undecided or default.
  enum class SpacingDecision {
    Preserve,  // keep original inter-token spacing
    Append,    // add onto current line, with appropriate amount of spacing
    Wrap,      // wrap onto new line, with appropriate amount of indentation
  };
  
  std::ostream& operator<<(std::ostream& stream, SpacingDecision);
  
  // Set of bound parameters for formatting around this token.
  // The fields here are related to InterTokenInfo.
  struct InterTokenDecision {
    // Number of spaces to insert, used when SpacingDecision is Append.
    int spaces = 0;
  
    // Choice of space formatting before this token.
    SpacingDecision action = SpacingDecision::Preserve;
  
    // When preserving spaces before this token, start from this offset.
    const char* preserved_space_start = nullptr;
  
    InterTokenDecision() = default;
  
    explicit InterTokenDecision(const InterTokenInfo&);
  };
  
  // FormattedToken represents re-formatted text, whose spacing/line-break
  // decisions have been bound.  The information in this struct can be derived
  // entirely from a PreFormatToken.
  struct FormattedToken {
    FormattedToken() = default;
  
    // Don't care what spacing decision is at this time, it will be populated
    // when reconstructing formatting decisions from StateNode.
    explicit FormattedToken(const PreFormatToken& ftoken)
        : token(ftoken.token), before(ftoken.before) {}
  
    // Reconstructs the original spacing that preceded this token.
    absl::string_view OriginalLeadingSpaces() const;
  
    // Print out formatted result after formatting decision optimization.
    std::ostream& FormattedText(std::ostream&) const;
  
    // The token this PreFormatToken holds. TokenInfo must outlive this object.
    const TokenInfo* token = nullptr;
  
    // Decision about what spaces to apply before printing this token.
    InterTokenDecision before;
  };
  
  std::ostream& operator<<(std::ostream& stream, const FormattedToken& token);
  
  }  // namespace verible
  
  #endif  // VERIBLE_COMMON_FORMATTING_FORMAT_TOKEN_H_
  