| /* Definitions for Ada expressions |
| |
| Copyright (C) 2020-2024 Free Software Foundation, Inc. |
| |
| This file is part of GDB. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| |
| #ifndef ADA_EXP_H |
| #define ADA_EXP_H |
| |
| #include "expop.h" |
| |
| extern struct value *ada_unop_neg (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg1); |
| extern struct value *ada_atr_tag (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg1); |
| extern struct value *ada_atr_size (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg1); |
| extern struct value *ada_abs (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg1); |
| extern struct value *ada_unop_in_range (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg1, struct type *type); |
| extern struct value *ada_mult_binop (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg1, struct value *arg2); |
| extern struct value *ada_equal_binop (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg1, struct value *arg2); |
| extern struct value *ada_ternop_slice (struct expression *exp, |
| enum noside noside, |
| struct value *array, |
| struct value *low_bound_val, |
| struct value *high_bound_val); |
| extern struct value *ada_binop_in_bounds (struct expression *exp, |
| enum noside noside, |
| struct value *arg1, |
| struct value *arg2, |
| int n); |
| extern struct value *ada_binop_minmax (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg1, |
| struct value *arg2); |
| extern struct value *ada_pos_atr (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg); |
| extern struct value *ada_atr_enum_rep (struct expression *exp, |
| enum noside noside, struct type *type, |
| struct value *arg); |
| extern struct value *ada_atr_enum_val (struct expression *exp, |
| enum noside noside, struct type *type, |
| struct value *arg); |
| extern struct value *ada_val_atr (struct expression *exp, |
| enum noside noside, struct type *type, |
| struct value *arg); |
| extern struct value *ada_binop_exp (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside, enum exp_opcode op, |
| struct value *arg1, struct value *arg2); |
| |
| namespace expr |
| { |
| |
| /* The base class for Ada type resolution. Ada operations that want |
| to participate in resolution implement this interface. */ |
| struct ada_resolvable |
| { |
| /* Resolve this object. EXP is the expression being resolved. |
| DEPROCEDURE_P is true if a symbol that refers to a zero-argument |
| function may be turned into a function call. PARSE_COMPLETION |
| and TRACKER are passed in from the parser context. CONTEXT_TYPE |
| is the expected type of the expression, or nullptr if none is |
| known. This method should return true if the operation should be |
| replaced by a function call with this object as the callee. */ |
| virtual bool resolve (struct expression *exp, |
| bool deprocedure_p, |
| bool parse_completion, |
| innermost_block_tracker *tracker, |
| struct type *context_type) = 0; |
| |
| /* Possibly replace this object with some other expression object. |
| This is like 'resolve', but can return a replacement. |
| |
| The default implementation calls 'resolve' and wraps this object |
| in a function call if that call returns true. OWNER is a |
| reference to the unique pointer that owns the 'this'; it can be |
| 'move'd from to construct the replacement. |
| |
| This should either return a new object, or OWNER -- never |
| nullptr. */ |
| |
| virtual operation_up replace (operation_up &&owner, |
| struct expression *exp, |
| bool deprocedure_p, |
| bool parse_completion, |
| innermost_block_tracker *tracker, |
| struct type *context_type); |
| }; |
| |
| /* In Ada, some generic operations must be wrapped with a handler that |
| handles some Ada-specific type conversions. */ |
| class ada_wrapped_operation |
| : public tuple_holding_operation<operation_up> |
| { |
| public: |
| |
| using tuple_holding_operation::tuple_holding_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| enum exp_opcode opcode () const override |
| { return std::get<0> (m_storage)->opcode (); } |
| |
| protected: |
| |
| void do_generate_ax (struct expression *exp, |
| struct agent_expr *ax, |
| struct axs_value *value, |
| struct type *cast_type) |
| override; |
| }; |
| |
| /* An Ada string constant. */ |
| class ada_string_operation |
| : public string_operation |
| { |
| public: |
| |
| using string_operation::string_operation; |
| |
| /* Return the underlying string. */ |
| const char *get_name () const |
| { |
| return std::get<0> (m_storage).c_str (); |
| } |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| }; |
| |
| /* The Ada TYPE'(EXP) construct. */ |
| class ada_qual_operation |
| : public tuple_holding_operation<operation_up, struct type *> |
| { |
| public: |
| |
| using tuple_holding_operation::tuple_holding_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| enum exp_opcode opcode () const override |
| { return UNOP_QUAL; } |
| }; |
| |
| /* Ternary in-range operator. */ |
| class ada_ternop_range_operation |
| : public tuple_holding_operation<operation_up, operation_up, operation_up> |
| { |
| public: |
| |
| using tuple_holding_operation::tuple_holding_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| enum exp_opcode opcode () const override |
| { return TERNOP_IN_RANGE; } |
| }; |
| |
| using ada_neg_operation = unop_operation<UNOP_NEG, ada_unop_neg>; |
| using ada_atr_tag_operation = unop_operation<OP_ATR_TAG, ada_atr_tag>; |
| using ada_atr_size_operation = unop_operation<OP_ATR_SIZE, ada_atr_size>; |
| using ada_abs_operation = unop_operation<UNOP_ABS, ada_abs>; |
| using ada_pos_operation = unop_operation<OP_ATR_POS, ada_pos_atr>; |
| |
| /* The in-range operation, given a type. */ |
| class ada_unop_range_operation |
| : public tuple_holding_operation<operation_up, struct type *> |
| { |
| public: |
| |
| using tuple_holding_operation::tuple_holding_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override |
| { |
| value *val = std::get<0> (m_storage)->evaluate (nullptr, exp, noside); |
| return ada_unop_in_range (expect_type, exp, noside, UNOP_IN_RANGE, |
| val, std::get<1> (m_storage)); |
| } |
| |
| enum exp_opcode opcode () const override |
| { return UNOP_IN_RANGE; } |
| }; |
| |
| /* The Ada + and - operators. */ |
| class ada_binop_addsub_operation |
| : public tuple_holding_operation<enum exp_opcode, operation_up, operation_up> |
| { |
| public: |
| |
| using tuple_holding_operation::tuple_holding_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| enum exp_opcode opcode () const override |
| { return std::get<0> (m_storage); } |
| }; |
| |
| using ada_binop_mul_operation = binop_operation<BINOP_MUL, ada_mult_binop>; |
| using ada_binop_div_operation = binop_operation<BINOP_DIV, ada_mult_binop>; |
| using ada_binop_rem_operation = binop_operation<BINOP_REM, ada_mult_binop>; |
| using ada_binop_mod_operation = binop_operation<BINOP_MOD, ada_mult_binop>; |
| |
| using ada_binop_min_operation = binop_operation<BINOP_MIN, ada_binop_minmax>; |
| using ada_binop_max_operation = binop_operation<BINOP_MAX, ada_binop_minmax>; |
| |
| using ada_binop_exp_operation = binop_operation<BINOP_EXP, ada_binop_exp>; |
| |
| /* Implement the equal and not-equal operations for Ada. */ |
| class ada_binop_equal_operation |
| : public tuple_holding_operation<enum exp_opcode, operation_up, operation_up> |
| { |
| public: |
| |
| using tuple_holding_operation::tuple_holding_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override |
| { |
| value *arg1 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside); |
| value *arg2 = std::get<2> (m_storage)->evaluate (arg1->type (), |
| exp, noside); |
| return ada_equal_binop (expect_type, exp, noside, std::get<0> (m_storage), |
| arg1, arg2); |
| } |
| |
| void do_generate_ax (struct expression *exp, |
| struct agent_expr *ax, |
| struct axs_value *value, |
| struct type *cast_type) |
| override |
| { |
| gen_expr_binop (exp, opcode (), |
| std::get<1> (this->m_storage).get (), |
| std::get<2> (this->m_storage).get (), |
| ax, value); |
| } |
| |
| enum exp_opcode opcode () const override |
| { return std::get<0> (m_storage); } |
| }; |
| |
| /* Ada array- or string-slice operation. */ |
| class ada_ternop_slice_operation |
| : public maybe_constant_operation<operation_up, operation_up, operation_up>, |
| public ada_resolvable |
| { |
| public: |
| |
| using maybe_constant_operation::maybe_constant_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override |
| { |
| value *array = std::get<0> (m_storage)->evaluate (nullptr, exp, noside); |
| value *low = std::get<1> (m_storage)->evaluate (nullptr, exp, noside); |
| value *high = std::get<2> (m_storage)->evaluate (nullptr, exp, noside); |
| return ada_ternop_slice (exp, noside, array, low, high); |
| } |
| |
| enum exp_opcode opcode () const override |
| { return TERNOP_SLICE; } |
| |
| bool resolve (struct expression *exp, |
| bool deprocedure_p, |
| bool parse_completion, |
| innermost_block_tracker *tracker, |
| struct type *context_type) override; |
| }; |
| |
| /* Implement BINOP_IN_BOUNDS for Ada. */ |
| class ada_binop_in_bounds_operation |
| : public maybe_constant_operation<operation_up, operation_up, int> |
| { |
| public: |
| |
| using maybe_constant_operation::maybe_constant_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override |
| { |
| value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside); |
| value *arg2 = std::get<1> (m_storage)->evaluate (nullptr, exp, noside); |
| return ada_binop_in_bounds (exp, noside, arg1, arg2, |
| std::get<2> (m_storage)); |
| } |
| |
| enum exp_opcode opcode () const override |
| { return BINOP_IN_BOUNDS; } |
| }; |
| |
| /* Implement several unary Ada OP_ATR_* operations. */ |
| class ada_unop_atr_operation |
| : public maybe_constant_operation<operation_up, enum exp_opcode, int> |
| { |
| public: |
| |
| using maybe_constant_operation::maybe_constant_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| enum exp_opcode opcode () const override |
| { return std::get<1> (m_storage); } |
| }; |
| |
| /* Variant of var_value_operation for Ada. */ |
| class ada_var_value_operation |
| : public var_value_operation, public ada_resolvable |
| { |
| public: |
| |
| using var_value_operation::var_value_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| value *evaluate_for_cast (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| const block *get_block () const |
| { return std::get<0> (m_storage).block; } |
| |
| bool resolve (struct expression *exp, |
| bool deprocedure_p, |
| bool parse_completion, |
| innermost_block_tracker *tracker, |
| struct type *context_type) override; |
| |
| protected: |
| |
| void do_generate_ax (struct expression *exp, |
| struct agent_expr *ax, |
| struct axs_value *value, |
| struct type *cast_type) |
| override; |
| }; |
| |
| /* Variant of var_msym_value_operation for Ada. */ |
| class ada_var_msym_value_operation |
| : public var_msym_value_operation |
| { |
| public: |
| |
| using var_msym_value_operation::var_msym_value_operation; |
| |
| value *evaluate_for_cast (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| protected: |
| |
| using operation::do_generate_ax; |
| }; |
| |
| typedef struct value *ada_atr_ftype (struct expression *exp, |
| enum noside noside, |
| struct type *type, |
| struct value *arg); |
| |
| /* Implement several Ada attributes. */ |
| template<ada_atr_ftype FUNC> |
| class ada_atr_operation |
| : public tuple_holding_operation<struct type *, operation_up> |
| { |
| public: |
| |
| using tuple_holding_operation::tuple_holding_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override |
| { |
| value *arg = std::get<1> (m_storage)->evaluate (nullptr, exp, noside); |
| return FUNC (exp, noside, std::get<0> (m_storage), arg); |
| } |
| |
| enum exp_opcode opcode () const override |
| { |
| /* The value here generally doesn't matter. */ |
| return OP_ATR_VAL; |
| } |
| }; |
| |
| using ada_atr_val_operation = ada_atr_operation<ada_val_atr>; |
| using ada_atr_enum_rep_operation = ada_atr_operation<ada_atr_enum_rep>; |
| using ada_atr_enum_val_operation = ada_atr_operation<ada_atr_enum_val>; |
| |
| /* The indirection operator for Ada. */ |
| class ada_unop_ind_operation |
| : public unop_ind_base_operation |
| { |
| public: |
| |
| using unop_ind_base_operation::unop_ind_base_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| }; |
| |
| /* Implement STRUCTOP_STRUCT for Ada. */ |
| class ada_structop_operation |
| : public structop_base_operation |
| { |
| public: |
| |
| using structop_base_operation::structop_base_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| enum exp_opcode opcode () const override |
| { return STRUCTOP_STRUCT; } |
| |
| /* Set the completion prefix. */ |
| void set_prefix (std::string &&prefix) |
| { |
| m_prefix = std::move (prefix); |
| } |
| |
| bool complete (struct expression *exp, completion_tracker &tracker) override |
| { |
| return structop_base_operation::complete (exp, tracker, m_prefix.c_str ()); |
| } |
| |
| void dump (struct ui_file *stream, int depth) const override |
| { |
| structop_base_operation::dump (stream, depth); |
| dump_for_expression (stream, depth + 1, m_prefix); |
| } |
| |
| private: |
| |
| /* We may need to provide a prefix to field name completion. See |
| ada-exp.y:find_completion_bounds for details. */ |
| std::string m_prefix; |
| }; |
| |
| /* Function calls for Ada. */ |
| class ada_funcall_operation |
| : public tuple_holding_operation<operation_up, std::vector<operation_up>>, |
| public ada_resolvable |
| { |
| public: |
| |
| using tuple_holding_operation::tuple_holding_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| bool resolve (struct expression *exp, |
| bool deprocedure_p, |
| bool parse_completion, |
| innermost_block_tracker *tracker, |
| struct type *context_type) override; |
| |
| enum exp_opcode opcode () const override |
| { return OP_FUNCALL; } |
| }; |
| |
| /* An Ada assignment operation. */ |
| class ada_assign_operation |
| : public assign_operation |
| { |
| public: |
| |
| using assign_operation::assign_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| enum exp_opcode opcode () const override |
| { return BINOP_ASSIGN; } |
| |
| value *current () |
| { return m_current; } |
| |
| /* A helper function for the parser to evaluate just the LHS of the |
| assignment. */ |
| value *eval_for_resolution (struct expression *exp) |
| { |
| return std::get<0> (m_storage)->evaluate (nullptr, exp, |
| EVAL_AVOID_SIDE_EFFECTS); |
| } |
| |
| /* The parser must construct the assignment node before parsing the |
| RHS, so that '@' can access the assignment, so this helper |
| function is needed to set the RHS after construction. */ |
| void set_rhs (operation_up rhs) |
| { |
| std::get<1> (m_storage) = std::move (rhs); |
| } |
| |
| private: |
| |
| /* Temporary storage for the value of the left-hand-side. */ |
| value *m_current = nullptr; |
| }; |
| |
| /* Implement the Ada target name symbol ('@'). This is used to refer |
| to the LHS of an assignment from the RHS. */ |
| class ada_target_operation : public operation |
| { |
| public: |
| |
| explicit ada_target_operation (ada_assign_operation *lhs) |
| : m_lhs (lhs) |
| { } |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override |
| { |
| if (noside == EVAL_AVOID_SIDE_EFFECTS) |
| return m_lhs->eval_for_resolution (exp); |
| return m_lhs->current (); |
| } |
| |
| enum exp_opcode opcode () const override |
| { |
| /* It doesn't really matter. */ |
| return OP_VAR_VALUE; |
| } |
| |
| void dump (struct ui_file *stream, int depth) const override |
| { |
| gdb_printf (stream, _("%*sAda target symbol '@'\n"), depth, ""); |
| } |
| |
| private: |
| |
| /* The left hand side of the assignment. */ |
| ada_assign_operation *m_lhs; |
| }; |
| |
| /* When constructing an aggregate, an object of this type is created |
| to track the needed state. */ |
| |
| struct aggregate_assigner |
| { |
| /* An lvalue containing LHS (possibly LHS itself). */ |
| value *container; |
| |
| /* An lvalue of record or array type; this is the object being |
| assigned to. */ |
| value *lhs; |
| |
| /* The expression being evaluated. */ |
| expression *exp; |
| |
| /* The bounds of LHS. This is used by the 'others' component. */ |
| LONGEST low; |
| LONGEST high; |
| |
| /* This indicates which sub-components have already been assigned |
| to. */ |
| std::vector<LONGEST> indices; |
| |
| private: |
| |
| /* The current index value. This is only valid during the 'assign' |
| operation and is part of the implementation of iterated component |
| association. */ |
| LONGEST m_current_index = 0; |
| |
| public: |
| |
| /* Assign the result of evaluating ARG to the INDEXth component of |
| LHS (a simple array or a record). Does not modify the inferior's |
| memory, nor does it modify LHS (unless LHS == CONTAINER). */ |
| void assign (LONGEST index, operation_up &arg); |
| |
| /* Add the interval [FROM .. TO] to the sorted set of intervals |
| [ INDICES[0] .. INDICES[1] ],... The resulting intervals do not |
| overlap. */ |
| void add_interval (LONGEST low, LONGEST high); |
| |
| /* Return the current index as a value, using the index type of |
| LHS. */ |
| value *current_value () const; |
| }; |
| |
| /* This abstract class represents a single component in an Ada |
| aggregate assignment. */ |
| class ada_component |
| { |
| public: |
| |
| /* Assign to ASSIGNER. */ |
| virtual void assign (aggregate_assigner &assigner) = 0; |
| |
| /* Same as operation::uses_objfile. */ |
| virtual bool uses_objfile (struct objfile *objfile) = 0; |
| |
| /* Same as operation::dump. */ |
| virtual void dump (ui_file *stream, int depth) = 0; |
| |
| virtual ~ada_component () = default; |
| |
| protected: |
| |
| ada_component () = default; |
| DISABLE_COPY_AND_ASSIGN (ada_component); |
| }; |
| |
| /* Unique pointer specialization for Ada assignment components. */ |
| typedef std::unique_ptr<ada_component> ada_component_up; |
| |
| /* An operation that holds a single component. */ |
| class ada_aggregate_operation |
| : public tuple_holding_operation<ada_component_up> |
| { |
| public: |
| |
| using tuple_holding_operation::tuple_holding_operation; |
| |
| /* Assuming that LHS represents an lvalue having a record or array |
| type, evaluate an assignment of this aggregate's value to LHS. |
| CONTAINER is an lvalue containing LHS (possibly LHS itself). |
| Does not modify the inferior's memory, nor does it modify the |
| contents of LHS (unless == CONTAINER). Returns the modified |
| CONTAINER. */ |
| |
| value *assign_aggregate (struct value *container, |
| struct value *lhs, |
| struct expression *exp); |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override |
| { |
| error (_("Aggregates only allowed on the right of an assignment")); |
| } |
| |
| enum exp_opcode opcode () const override |
| { return OP_AGGREGATE; } |
| }; |
| |
| /* A component holding a vector of other components to assign. */ |
| class ada_aggregate_component : public ada_component |
| { |
| public: |
| |
| explicit ada_aggregate_component (std::vector<ada_component_up> &&components) |
| : m_components (std::move (components)) |
| { |
| } |
| |
| /* This is the "with delta" form -- BASE is the base expression. */ |
| ada_aggregate_component (operation_up &&base, |
| std::vector<ada_component_up> &&components); |
| |
| void assign (aggregate_assigner &assigner) override; |
| |
| bool uses_objfile (struct objfile *objfile) override; |
| |
| void dump (ui_file *stream, int depth) override; |
| |
| private: |
| |
| /* If the assignment has a "with delta" clause, this is the |
| base expression. */ |
| operation_up m_base; |
| /* The individual components to assign. */ |
| std::vector<ada_component_up> m_components; |
| }; |
| |
| /* A component that assigns according to a provided index (which is |
| relative to the "low" value). */ |
| class ada_positional_component : public ada_component |
| { |
| public: |
| |
| ada_positional_component (int index, operation_up &&op) |
| : m_index (index), |
| m_op (std::move (op)) |
| { |
| } |
| |
| void assign (aggregate_assigner &assigner) override; |
| |
| bool uses_objfile (struct objfile *objfile) override; |
| |
| void dump (ui_file *stream, int depth) override; |
| |
| private: |
| |
| int m_index; |
| operation_up m_op; |
| }; |
| |
| /* A component which handles an "others" clause. */ |
| class ada_others_component : public ada_component |
| { |
| public: |
| |
| explicit ada_others_component (operation_up &&op) |
| : m_op (std::move (op)) |
| { |
| } |
| |
| void assign (aggregate_assigner &assigner) override; |
| |
| bool uses_objfile (struct objfile *objfile) override; |
| |
| void dump (ui_file *stream, int depth) override; |
| |
| private: |
| |
| operation_up m_op; |
| }; |
| |
| /* An interface that represents an association that is used in |
| aggregate assignment. */ |
| class ada_association |
| { |
| public: |
| |
| /* Like ada_component::assign, but takes an operation as a |
| parameter. The operation is evaluated and then assigned into |
| ASSIGNER according to the rules of the concrete |
| implementation. */ |
| virtual void assign (aggregate_assigner &assigner, operation_up &op) = 0; |
| |
| /* Same as operation::uses_objfile. */ |
| virtual bool uses_objfile (struct objfile *objfile) = 0; |
| |
| /* Same as operation::dump. */ |
| virtual void dump (ui_file *stream, int depth) = 0; |
| |
| virtual ~ada_association () = default; |
| |
| protected: |
| |
| ada_association () = default; |
| DISABLE_COPY_AND_ASSIGN (ada_association); |
| }; |
| |
| /* Unique pointer specialization for Ada assignment associations. */ |
| typedef std::unique_ptr<ada_association> ada_association_up; |
| |
| /* A component that holds a vector of associations and an operation. |
| The operation is re-evaluated for each choice. */ |
| class ada_choices_component : public ada_component |
| { |
| public: |
| |
| explicit ada_choices_component (operation_up &&op) |
| : m_op (std::move (op)) |
| { |
| } |
| |
| /* Set the vector of associations. This is done separately from the |
| constructor because it was simpler for the implementation of the |
| parser. */ |
| void set_associations (std::vector<ada_association_up> &&assoc) |
| { |
| m_assocs = std::move (assoc); |
| } |
| |
| /* Set the underlying operation */ |
| void set_operation (operation_up op) |
| { m_op = std::move (op); } |
| |
| /* Set the index variable name for an iterated association. */ |
| void set_name (std::string &&name) |
| { m_name = std::move (name); } |
| |
| /* The name of this choice component. This is empty unless this is |
| an iterated association. */ |
| const std::string &name () const |
| { return m_name; } |
| |
| void assign (aggregate_assigner &assigner) override; |
| |
| bool uses_objfile (struct objfile *objfile) override; |
| |
| void dump (ui_file *stream, int depth) override; |
| |
| /* Return the current value of the index variable. This may only be |
| called underneath a call to 'assign'. */ |
| value *current_value () const |
| { return m_assigner->current_value (); } |
| |
| private: |
| |
| std::vector<ada_association_up> m_assocs; |
| operation_up m_op; |
| |
| /* Name of the variable used for iteration. This isn't needed for |
| evaluation, only for debug dumping. This is the empty string for |
| ordinary (non-iterated) choices. */ |
| std::string m_name; |
| |
| /* A pointer to the current assignment operation; only valid when in |
| a call to the 'assign' method. This is used to find the index |
| variable value during the evaluation of the RHS of the =>, via |
| ada_index_var_operation. */ |
| const aggregate_assigner *m_assigner = nullptr; |
| }; |
| |
| /* Implement the index variable for iterated component |
| association. */ |
| class ada_index_var_operation : public operation |
| { |
| public: |
| |
| ada_index_var_operation () |
| { } |
| |
| /* Link this variable to the choices object. May only be called |
| once. */ |
| void set_choices (ada_choices_component *var) |
| { |
| gdb_assert (m_var == nullptr && var != nullptr); |
| m_var = var; |
| } |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| |
| enum exp_opcode opcode () const override |
| { |
| /* It doesn't really matter. */ |
| return OP_VAR_VALUE; |
| } |
| |
| void dump (struct ui_file *stream, int depth) const override; |
| |
| private: |
| |
| /* The choices component that introduced the index variable. */ |
| ada_choices_component *m_var = nullptr; |
| }; |
| |
| /* An association that uses a discrete range. */ |
| class ada_discrete_range_association : public ada_association |
| { |
| public: |
| |
| ada_discrete_range_association (operation_up &&low, operation_up &&high) |
| : m_low (std::move (low)), |
| m_high (std::move (high)) |
| { |
| } |
| |
| void assign (aggregate_assigner &assigner, operation_up &op) override; |
| |
| bool uses_objfile (struct objfile *objfile) override; |
| |
| void dump (ui_file *stream, int depth) override; |
| |
| private: |
| |
| operation_up m_low; |
| operation_up m_high; |
| }; |
| |
| /* An association that uses a name. The name may be an expression |
| that evaluates to an integer (for arrays), or an Ada string or |
| variable value operation. */ |
| class ada_name_association : public ada_association |
| { |
| public: |
| |
| explicit ada_name_association (operation_up val) |
| : m_val (std::move (val)) |
| { |
| } |
| |
| void assign (aggregate_assigner &assigner, operation_up &op) override; |
| |
| bool uses_objfile (struct objfile *objfile) override; |
| |
| void dump (ui_file *stream, int depth) override; |
| |
| private: |
| |
| operation_up m_val; |
| }; |
| |
| /* A character constant expression. This is a separate operation so |
| that it can participate in resolution, so that TYPE'(CST) can |
| work correctly for enums with character enumerators. */ |
| class ada_char_operation : public long_const_operation, |
| public ada_resolvable |
| { |
| public: |
| |
| using long_const_operation::long_const_operation; |
| |
| bool resolve (struct expression *exp, |
| bool deprocedure_p, |
| bool parse_completion, |
| innermost_block_tracker *tracker, |
| struct type *context_type) override |
| { |
| /* This should never be called, because this class also implements |
| 'replace'. */ |
| gdb_assert_not_reached ("unexpected call"); |
| } |
| |
| operation_up replace (operation_up &&owner, |
| struct expression *exp, |
| bool deprocedure_p, |
| bool parse_completion, |
| innermost_block_tracker *tracker, |
| struct type *context_type) override; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| }; |
| |
| class ada_concat_operation : public concat_operation |
| { |
| public: |
| |
| using concat_operation::concat_operation; |
| |
| value *evaluate (struct type *expect_type, |
| struct expression *exp, |
| enum noside noside) override; |
| }; |
| |
| } /* namespace expr */ |
| |
| #endif /* ADA_EXP_H */ |