//===-- DILEval.h -----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_VALUEOBJECT_DILEVAL_H
#define LLDB_VALUEOBJECT_DILEVAL_H

#include "lldb/ValueObject/DILAST.h"
#include "lldb/ValueObject/DILParser.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <memory>
#include <vector>

namespace lldb_private::dil {

/// Given the name of an identifier (variable name, member name, type name,
/// etc.), find the ValueObject for that name (if it exists), excluding global
/// variables, and create and return an IdentifierInfo object containing all
/// the relevant information about that object (for DIL parsing and
/// evaluating).
lldb::ValueObjectSP LookupIdentifier(llvm::StringRef name_ref,
                                     StackFrame &stack_frame,
                                     lldb::DynamicValueType use_dynamic);

/// Given the name of an identifier, check to see if it matches the name of a
/// global variable. If so, find the ValueObject for that global variable, and
/// create and return an IdentifierInfo object containing all the relevant
/// information about it.
lldb::ValueObjectSP LookupGlobalIdentifier(llvm::StringRef name_ref,
                                           StackFrame &stack_frame,
                                           lldb::TargetSP target_sp,
                                           lldb::DynamicValueType use_dynamic);

/// Given the name of an identifier, attempt to find an enumeration value.
/// If found, return a ValueObject with a const scalar value of the enum.
lldb::ValueObjectSP LookupEnumValue(llvm::StringRef name_ref,
                                    ExecutionContextScope &ctx_scope);

class Interpreter : Visitor {
public:
  Interpreter(lldb::TargetSP target, llvm::StringRef expr,
              StackFrame &stack_frame, lldb::DynamicValueType use_dynamic,
              uint32_t options);

  /// Evaluate an ASTNode.
  /// \returns A non-null lldb::ValueObjectSP or an Error.
  llvm::Expected<lldb::ValueObjectSP> Evaluate(const ASTNode &node);

private:
  /// Evaluate an ASTNode. If the result is a reference, it is also
  /// dereferenced using ValueObject::Dereference.
  /// \returns A non-null lldb::ValueObjectSP or an Error.
  llvm::Expected<lldb::ValueObjectSP>
  EvaluateAndDereference(const ASTNode &node);
  llvm::Expected<lldb::ValueObjectSP>
  Visit(const IdentifierNode &node) override;
  llvm::Expected<lldb::ValueObjectSP> Visit(const MemberOfNode &node) override;
  llvm::Expected<lldb::ValueObjectSP> Visit(const UnaryOpNode &node) override;
  llvm::Expected<lldb::ValueObjectSP> Visit(const BinaryOpNode &node) override;
  llvm::Expected<lldb::ValueObjectSP>
  Visit(const ArraySubscriptNode &node) override;
  llvm::Expected<lldb::ValueObjectSP>
  Visit(const BitFieldExtractionNode &node) override;
  llvm::Expected<lldb::ValueObjectSP>
  Visit(const IntegerLiteralNode &node) override;
  llvm::Expected<lldb::ValueObjectSP>
  Visit(const FloatLiteralNode &node) override;
  llvm::Expected<lldb::ValueObjectSP>
  Visit(const BooleanLiteralNode &node) override;
  llvm::Expected<lldb::ValueObjectSP> Visit(const CastNode &node) override;

  /// Perform usual unary conversions on a value. At the moment this
  /// includes array-to-pointer and integral promotion for eligible types.
  llvm::Expected<lldb::ValueObjectSP>
  UnaryConversion(lldb::ValueObjectSP valobj, uint32_t location);

  /// If `lhs_type` is unsigned and `rhs_type` is signed, check whether it
  /// can represent all of the values of `lhs_type`.
  /// If not, then promote `rhs_type` to the unsigned version of its type.
  /// This expects that Rank(lhs_type) < Rank(rhs_type).
  /// \returns Unchanged `rhs_type` or promoted unsigned version.
  llvm::Expected<CompilerType> PromoteSignedInteger(CompilerType &lhs_type,
                                                    CompilerType &rhs_type);

  /// Perform an arithmetic conversion on two values from an arithmetic
  /// operation.
  llvm::Expected<CompilerType> ArithmeticConversion(lldb::ValueObjectSP &lhs,
                                                    lldb::ValueObjectSP &rhs,
                                                    uint32_t location);

  /// Add or subtract the offset to the pointer according to the pointee type
  /// byte size.
  /// \returns A new `ValueObject` with a new pointer value.
  llvm::Expected<lldb::ValueObjectSP> PointerOffset(lldb::ValueObjectSP ptr,
                                                    lldb::ValueObjectSP offset,
                                                    BinaryOpKind operation,
                                                    uint32_t location);

  llvm::Expected<lldb::ValueObjectSP> EvaluateScalarOp(BinaryOpKind kind,
                                                       lldb::ValueObjectSP lhs,
                                                       lldb::ValueObjectSP rhs,
                                                       CompilerType result_type,
                                                       uint32_t location);
  llvm::Expected<lldb::ValueObjectSP>
  EvaluateBinaryShift(BinaryOpKind kind, lldb::ValueObjectSP lhs,
                      lldb::ValueObjectSP rhs, uint32_t location);
  llvm::Expected<lldb::ValueObjectSP>
  EvaluateBinaryAddition(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
                         uint32_t location);

  llvm::Expected<lldb::ValueObjectSP>
  EvaluateBinarySubtraction(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
                            uint32_t location);

  llvm::Expected<lldb::ValueObjectSP>
  EvaluateBinaryMultiplication(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
                               uint32_t location);
  llvm::Expected<lldb::ValueObjectSP>
  EvaluateBinaryDivision(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
                         uint32_t location);
  llvm::Expected<lldb::ValueObjectSP>
  EvaluateBinaryRemainder(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
                          uint32_t location);
  llvm::Expected<CompilerType>
  PickIntegerType(lldb::TypeSystemSP type_system, ExecutionContextScope &ctx,
                  const IntegerLiteralNode &literal);

  llvm::Expected<lldb::ValueObjectSP>
  EvaluateAssignment(lldb::ValueObjectSP lhs, lldb::ValueObjectSP rhs,
                     uint32_t location);

  /// A helper function for VerifyCastType (below). This performs
  /// arithmetic-specific checks. It should only be called if the target_type
  /// is a scalar type.
  llvm::Expected<CastKind> VerifyArithmeticCast(CompilerType source_type,
                                                CompilerType target_type,
                                                int location);

  /// As a preparation for type casting, compare the requested 'target' type
  /// of the cast with the type of the operand to be cast. If the cast is
  /// allowed, return the appropriate CastKind for the cast; otherwise return
  /// an error.
  llvm::Expected<CastKind> VerifyCastType(lldb::ValueObjectSP operand,
                                          CompilerType source_type,
                                          CompilerType target_type,
                                          int location);

  // Used by the interpreter to create objects, perform casts, etc.
  lldb::TargetSP m_target;
  llvm::StringRef m_expr;
  lldb::ValueObjectSP m_scope;
  StackFrame &m_stack_frame;
  lldb::DynamicValueType m_use_dynamic;
  bool m_use_synthetic;
  bool m_check_ptr_vs_member;
  bool m_allow_var_updates;
  bool m_allow_globals = true;
};

} // namespace lldb_private::dil

#endif // LLDB_VALUEOBJECT_DILEVAL_H
