text: /// \file
  /// Class Instr - the object representing an instruction.
  
  #ifndef ILANG_ILA_INSTR_H__
  #define ILANG_ILA_INSTR_H__
  
  #include <memory>
  #include <string>
  
  #include <ilang/ila/instrlike/packagedinstr.h>
  #include <ilang/ila/instrtemplate.h>
  
  /// \namespace ilang
  namespace ilang {
  
  // Forward declaration for adding host ila.
  class InstrLvlAbs;
  
  /// \brief The class for the Instruction. An Instr object contains:
  /// - the decode function
  /// - a set of update functions for the state variables
  /// - several attributes, e.g. view
  class Instr : public PackagedInstr, public std::enable_shared_from_this<Instr> {
  public:
    /// Pointer type for normal use of Instr.
    typedef std::shared_ptr<Instr> InstrPtr;
    /// Pointer type for read-only use of Instr.
    typedef std::shared_ptr<const Instr> InstrCnstPtr;
  
  private:
    /// Type for storing a set of Expr.
    typedef std::map<std::string, ExprPtr> ExprPtrMap;
  
  public:
  
    using std::enable_shared_from_this<Instr>::shared_from_this;
    using std::enable_shared_from_this<Instr>::weak_from_this;
  
    // ------------------------- CONSTRUCTOR/DESTRUCTOR ----------------------- //
    /// Constructor with the ast simplifier.
    Instr(const std::string& name, const InstrLvlAbsPtr& host = nullptr);
    /// Default destructor.
    ~Instr();
  
    // ------------------------- HELPERS -------------------------------------- //
    /// \brief Create a new instruction (Instr) binded with the host. Used
    /// for hiding implementation specific type details.
    static InstrPtr New(const std::string& name, InstrLvlAbsPtr host = nullptr);
  
    // ------------------------- ACCESSORS/MUTATORS --------------------------- //
    /// \brief Set the update function for the state variable specified by name.
    /// \param[in] name the name of the state variable.
    /// \param[in] update the update function expression (same type as state).
    void set_update(const std::string& name, const ExprPtr& update);
  
    /// \brief Set the update function for the state variable specified by var
    /// pointer.
    /// \param[in] state the pointer to the state variable.
    /// \param[in] update the update function expression (same type as state).
    void set_update(const ExprPtr& state, const ExprPtr& update);
  
    /// \brief Set the update function for the state object specified by var
    /// container pointer.
    /// \param[in] state the pointer to the state object.
    /// \param[in] update the update function expression (same type as state).
    void set_update(const VarContainerPtr& state, const VarContainerPtr& update);
  
    /// \brief Return the update function for the state specified by name.
    /// \param[in] name the name of the state variable.
    /// \return the state update function.
    ExprPtr update(const std::string& name) const;
  
    /// \brief Return the update function for the state specified by var pointer.
    /// \param[in] state the pointer to the state variable.
    ExprPtr update(const ExprPtr& state) const;
  
    /// \brief Return the update function for the state object specified by the 
    /// given var container pointer.
    /// \param[in] state the pointer to the state variable.
    VarContainerPtr update(const VarContainerPtr& state) const;
  
    /// \brief Sets up to call an instance of the given instruction template
    /// \param[in] instr
    void prepare_template(
      const InstrTemplatePtr& instr_template, 
      const VarContainerPtr& state_args_to_update, 
      const VarContainerPtr& state_args_to_read,
      const VarContainerPtr& input_args_to_read) const;
  
    /// \brief return the (potentially) updated state of this function
    StateNameSet updated_states() const;
  
    /// \brief return the (potentially) used/updated variables of this function
    StateNameSet used_variables() const;
  
    // ------------------------- METHODS -------------------------------------- //
    /// \brief Overwrite update function for the state variable specified by name.
    /// \param[in] name the name of the state variable.
    /// \param[in] update the update function expression (same type as state).
    void ForceAddUpdate(const std::string& name, const ExprPtr& update);
  
    /// \brief Does nothing because this instruction should already be added to host. 
    inline void Unpack() {}
  
  private:
    // ------------------------- MEMBERS -------------------------------------- //
    /// The set of update functions, mapped by name.
    ExprPtrMap updates_;
  
    /// whether or not a template has been prepared
    bool template_prepped_;
  
  }; // class Instr
  
  /// Pointer type for normal use of Instr.
  typedef Instr::InstrPtr InstrPtr;
  /// Pointer type for read-only use of Instr.
  typedef Instr::InstrCnstPtr InstrCnstPtr;
  /// Type for storing a set of Instr.
  typedef std::vector<InstrPtr> InstrVec;
  
  } // namespace ilang
  
  #endif // ILNAG_ILA_INSTR_H__
  