Convert rust-exp.y to use operations

This converts the Rust parser to generate operations rather than
exp_elements.

The Rust parser already made its own AST, that it then lowered to GDB
expressions.  Ironically, this made conversion trickier, rather than
simpler, than the other parsers, primarily due to the way that binary
operations were lowered.  Perhaps in the future, converting the Rust
parser to directly create operations while parsing would be
worthwhile.

gdb/ChangeLog
2021-03-08  Tom Tromey  <tom@tromey.com>

	* rust-exp.y: Create operations.
	(rust_parser::convert_params_to_expression): Change return type.
	(binop_maker_ftype): New typedef.
	(maker_map): New global.
	(rust_parser::convert_ast_to_expression): Change return type.
	(rust_language::parser): Update.
	(_initialize_rust_exp): Initialize maker_map.
This commit is contained in:
Tom Tromey
2021-03-08 07:27:57 -07:00
parent 4c5e7a930a
commit c1299a2344
2 changed files with 189 additions and 143 deletions

View File

@ -1,3 +1,13 @@
2021-03-08 Tom Tromey <tom@tromey.com>
* rust-exp.y: Create operations.
(rust_parser::convert_params_to_expression): Change return type.
(binop_maker_ftype): New typedef.
(maker_map): New global.
(rust_parser::convert_ast_to_expression): Change return type.
(rust_language::parser): Update.
(_initialize_rust_exp): Initialize maker_map.
2021-03-08 Tom Tromey <tom@tromey.com> 2021-03-08 Tom Tromey <tom@tromey.com>
* stap-probe.c (binop_maker_ftype): New typedef. * stap-probe.c (binop_maker_ftype): New typedef.

View File

@ -41,6 +41,8 @@
#include "gdbsupport/selftest.h" #include "gdbsupport/selftest.h"
#include "value.h" #include "value.h"
#include "gdbarch.h" #include "gdbarch.h"
#include "rust-exp.h"
#include <unordered_map>
#define GDB_YY_REMAP_PREFIX rust #define GDB_YY_REMAP_PREFIX rust
#include "yy-remap.h" #include "yy-remap.h"
@ -246,11 +248,11 @@ struct rust_parser
std::vector<struct type *> convert_params_to_types (rust_op_vector *params); std::vector<struct type *> convert_params_to_types (rust_op_vector *params);
struct type *convert_ast_to_type (const struct rust_op *operation); struct type *convert_ast_to_type (const struct rust_op *operation);
const char *convert_name (const struct rust_op *operation); const char *convert_name (const struct rust_op *operation);
void convert_params_to_expression (rust_op_vector *params, std::vector<expr::operation_up> convert_params_to_expression
const struct rust_op *top); (rust_op_vector *params, const struct rust_op *top);
void convert_ast_to_expression (const struct rust_op *operation, expr::operation_up convert_ast_to_expression (const struct rust_op *opn,
const struct rust_op *top, const struct rust_op *top,
bool want_type = false); bool want_type = false);
struct rust_op *ast_basic_type (enum type_code typecode); struct rust_op *ast_basic_type (enum type_code typecode);
const struct rust_op *ast_operation (enum exp_opcode opcode, const struct rust_op *ast_operation (enum exp_opcode opcode,
@ -2183,14 +2185,25 @@ rust_parser::convert_name (const struct rust_op *operation)
/* A helper function that converts a vec of rust_ops to a gdb /* A helper function that converts a vec of rust_ops to a gdb
expression. */ expression. */
void std::vector<expr::operation_up>
rust_parser::convert_params_to_expression (rust_op_vector *params, rust_parser::convert_params_to_expression (rust_op_vector *params,
const struct rust_op *top) const struct rust_op *top)
{ {
std::vector<expr::operation_up> result;
for (const rust_op *elem : *params) for (const rust_op *elem : *params)
convert_ast_to_expression (elem, top); result.push_back (convert_ast_to_expression (elem, top));
result.shrink_to_fit ();
return result;
} }
typedef expr::operation_up binop_maker_ftype (expr::operation_up &&,
expr::operation_up &&);
/* Map from an expression opcode to a function that will create an
instance of the appropriate operation subclass. Only binary
operations are handled this way. */
static std::unordered_map<exp_opcode, binop_maker_ftype *> maker_map;
/* Lower a rust_op to a gdb expression. STATE is the parser state. /* Lower a rust_op to a gdb expression. STATE is the parser state.
OPERATION is the operation to lower. TOP is a pointer to the OPERATION is the operation to lower. TOP is a pointer to the
top-most operation; it is used to handle the special case where the top-most operation; it is used to handle the special case where the
@ -2200,62 +2213,87 @@ rust_parser::convert_params_to_expression (rust_op_vector *params,
erroring). If WANT_TYPE is set, then the similar TOP handling is erroring). If WANT_TYPE is set, then the similar TOP handling is
not done. */ not done. */
void expr::operation_up
rust_parser::convert_ast_to_expression (const struct rust_op *operation, rust_parser::convert_ast_to_expression (const struct rust_op *operation,
const struct rust_op *top, const struct rust_op *top,
bool want_type) bool want_type)
{ {
using namespace expr;
switch (operation->opcode) switch (operation->opcode)
{ {
case OP_LONG: case OP_LONG:
write_exp_elt_opcode (pstate, OP_LONG); return operation_up
write_exp_elt_type (pstate, operation->left.typed_val_int.type); (new long_const_operation (operation->left.typed_val_int.type,
write_exp_elt_longcst (pstate, operation->left.typed_val_int.val); operation->left.typed_val_int.val));
write_exp_elt_opcode (pstate, OP_LONG);
break;
case OP_FLOAT: case OP_FLOAT:
write_exp_elt_opcode (pstate, OP_FLOAT); {
write_exp_elt_type (pstate, operation->left.typed_val_float.type); float_data data;
write_exp_elt_floatcst (pstate, operation->left.typed_val_float.val); memcpy (data.data (), operation->left.typed_val_float.val,
write_exp_elt_opcode (pstate, OP_FLOAT); sizeof (operation->left.typed_val_float.val));
break; return operation_up
(new float_const_operation (operation->left.typed_val_float.type,
data));
}
case STRUCTOP_STRUCT: case STRUCTOP_STRUCT:
{ {
convert_ast_to_expression (operation->left.op, top); operation_up lhs = convert_ast_to_expression (operation->left.op, top);
auto result = new rust_structop (std::move (lhs),
operation->right.sval.ptr);
if (operation->completing) if (operation->completing)
pstate->mark_struct_expression (); pstate->mark_struct_expression (result);
write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); return operation_up (result);
write_exp_string (pstate, operation->right.sval);
write_exp_elt_opcode (pstate, STRUCTOP_STRUCT);
} }
break;
case STRUCTOP_ANONYMOUS: case STRUCTOP_ANONYMOUS:
{ {
convert_ast_to_expression (operation->left.op, top); operation_up lhs = convert_ast_to_expression (operation->left.op, top);
write_exp_elt_opcode (pstate, STRUCTOP_ANONYMOUS); return operation_up
write_exp_elt_longcst (pstate, operation->right.typed_val_int.val); (new rust_struct_anon (operation->right.typed_val_int.val,
write_exp_elt_opcode (pstate, STRUCTOP_ANONYMOUS); std::move (lhs)));
} }
break;
case UNOP_SIZEOF: case UNOP_SIZEOF:
convert_ast_to_expression (operation->left.op, top, true); {
write_exp_elt_opcode (pstate, UNOP_SIZEOF); operation_up lhs = convert_ast_to_expression (operation->left.op, top,
break; true);
return operation_up
(new unop_sizeof_operation (std::move (lhs)));
}
case UNOP_PLUS: case UNOP_PLUS:
{
operation_up lhs = convert_ast_to_expression (operation->left.op, top);
return operation_up
(new unary_plus_operation (std::move (lhs)));
}
case UNOP_NEG: case UNOP_NEG:
{
operation_up lhs = convert_ast_to_expression (operation->left.op, top);
return operation_up
(new unary_neg_operation (std::move (lhs)));
}
case UNOP_COMPLEMENT: case UNOP_COMPLEMENT:
{
operation_up lhs = convert_ast_to_expression (operation->left.op, top);
return operation_up
(new rust_unop_compl_operation (std::move (lhs)));
}
case UNOP_IND: case UNOP_IND:
{
operation_up lhs = convert_ast_to_expression (operation->left.op, top);
return operation_up
(new rust_unop_ind_operation (std::move (lhs)));
}
case UNOP_ADDR: case UNOP_ADDR:
convert_ast_to_expression (operation->left.op, top); {
write_exp_elt_opcode (pstate, operation->opcode); operation_up lhs = convert_ast_to_expression (operation->left.op, top);
break; return operation_up
(new rust_unop_addr_operation (std::move (lhs)));
}
case BINOP_SUBSCRIPT: case BINOP_SUBSCRIPT:
case BINOP_MUL: case BINOP_MUL:
@ -2279,45 +2317,45 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
case BINOP_RSH: case BINOP_RSH:
case BINOP_ASSIGN: case BINOP_ASSIGN:
case OP_RUST_ARRAY: case OP_RUST_ARRAY:
convert_ast_to_expression (operation->left.op, top); {
convert_ast_to_expression (operation->right.op, top); operation_up lhs = convert_ast_to_expression (operation->left.op, top);
if (operation->compound_assignment) operation_up rhs = convert_ast_to_expression (operation->right.op,
{ top);
write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY); operation_up result;
write_exp_elt_opcode (pstate, operation->opcode); if (operation->compound_assignment)
write_exp_elt_opcode (pstate, BINOP_ASSIGN_MODIFY); result = (operation_up
} (new assign_modify_operation (operation->opcode,
else std::move (lhs),
write_exp_elt_opcode (pstate, operation->opcode); std::move (rhs))));
else
{
auto iter = maker_map.find (operation->opcode);
gdb_assert (iter != maker_map.end ());
result = iter->second (std::move (lhs), std::move (rhs));
}
if (operation->compound_assignment if (operation->compound_assignment
|| operation->opcode == BINOP_ASSIGN) || operation->opcode == BINOP_ASSIGN)
{ {
struct type *type; struct type *type
= language_lookup_primitive_type (pstate->language (),
pstate->gdbarch (),
"()");
type = language_lookup_primitive_type (pstate->language (), operation_up nil (new long_const_operation (type, 0));
pstate->gdbarch (), result.reset (new comma_operation (std::move (result),
"()"); std::move (nil)));
}
write_exp_elt_opcode (pstate, OP_LONG); return result;
write_exp_elt_type (pstate, type); }
write_exp_elt_longcst (pstate, 0);
write_exp_elt_opcode (pstate, OP_LONG);
write_exp_elt_opcode (pstate, BINOP_COMMA);
}
break;
case UNOP_CAST: case UNOP_CAST:
{ {
struct type *type = convert_ast_to_type (operation->right.op); struct type *type = convert_ast_to_type (operation->right.op);
operation_up lhs = convert_ast_to_expression (operation->left.op, top);
convert_ast_to_expression (operation->left.op, top); return operation_up (new unop_cast_operation (std::move (lhs), type));
write_exp_elt_opcode (pstate, UNOP_CAST);
write_exp_elt_type (pstate, type);
write_exp_elt_opcode (pstate, UNOP_CAST);
} }
break;
case OP_FUNCALL: case OP_FUNCALL:
{ {
@ -2339,42 +2377,39 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
if (!rust_tuple_struct_type_p (type)) if (!rust_tuple_struct_type_p (type))
error (_("Type %s is not a tuple struct"), varname); error (_("Type %s is not a tuple struct"), varname);
std::vector<std::pair<std::string, operation_up>> args
(params->size ());
for (int i = 0; i < params->size (); ++i) for (int i = 0; i < params->size (); ++i)
{ {
char *cell = get_print_cell (); char *cell = get_print_cell ();
operation_up op
= convert_ast_to_expression ((*params)[i], top);
xsnprintf (cell, PRINT_CELL_SIZE, "__%d", i); xsnprintf (cell, PRINT_CELL_SIZE, "__%d", i);
write_exp_elt_opcode (pstate, OP_NAME); args[i] = { cell, std::move (op) };
write_exp_string (pstate, make_stoken (cell));
write_exp_elt_opcode (pstate, OP_NAME);
convert_ast_to_expression ((*params)[i], top);
} }
write_exp_elt_opcode (pstate, OP_AGGREGATE); return make_operation<rust_aggregate_operation>
write_exp_elt_type (pstate, type); (type, operation_up (), std::move (args));
write_exp_elt_longcst (pstate, 2 * params->size ());
write_exp_elt_opcode (pstate, OP_AGGREGATE);
break;
} }
} }
} }
convert_ast_to_expression (operation->left.op, top); operation_up callee = convert_ast_to_expression (operation->left.op,
convert_params_to_expression (operation->right.params, top); top);
write_exp_elt_opcode (pstate, OP_FUNCALL); std::vector<operation_up> args
write_exp_elt_longcst (pstate, operation->right.params->size ()); = convert_params_to_expression (operation->right.params, top);
write_exp_elt_longcst (pstate, OP_FUNCALL); return make_operation<funcall_operation> (std::move (callee),
std::move (args));
} }
break;
case OP_ARRAY: case OP_ARRAY:
gdb_assert (operation->left.op == NULL); {
convert_params_to_expression (operation->right.params, top); gdb_assert (operation->left.op == NULL);
write_exp_elt_opcode (pstate, OP_ARRAY); std::vector<operation_up> subexps
write_exp_elt_longcst (pstate, 0); = convert_params_to_expression (operation->right.params, top);
write_exp_elt_longcst (pstate, operation->right.params->size () - 1); return make_operation<array_operation>
write_exp_elt_longcst (pstate, OP_ARRAY); (0, operation->right.params->size () - 1, std::move (subexps));
break; }
case OP_VAR_VALUE: case OP_VAR_VALUE:
{ {
@ -2383,20 +2418,16 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
if (operation->left.sval.ptr[0] == '$') if (operation->left.sval.ptr[0] == '$')
{ {
write_dollar_variable (pstate, operation->left.sval); pstate->push_dollar (operation->left.sval);
break; return pstate->pop ();
} }
varname = convert_name (operation); varname = convert_name (operation);
sym = lookup_symbol (varname, pstate->expression_context_block, sym = lookup_symbol (varname, pstate->expression_context_block,
VAR_DOMAIN); VAR_DOMAIN);
operation_up result;
if (sym.symbol != NULL && SYMBOL_CLASS (sym.symbol) != LOC_TYPEDEF) if (sym.symbol != NULL && SYMBOL_CLASS (sym.symbol) != LOC_TYPEDEF)
{ result.reset (new var_value_operation (sym.symbol, sym.block));
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
write_exp_elt_block (pstate, sym.block);
write_exp_elt_sym (pstate, sym.symbol);
write_exp_elt_opcode (pstate, OP_VAR_VALUE);
}
else else
{ {
struct type *type = NULL; struct type *type = NULL;
@ -2417,52 +2448,35 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
&& type->num_fields () == 0) && type->num_fields () == 0)
{ {
/* A unit-like struct. */ /* A unit-like struct. */
write_exp_elt_opcode (pstate, OP_AGGREGATE); result.reset (new rust_aggregate_operation (type, {}, {}));
write_exp_elt_type (pstate, type);
write_exp_elt_longcst (pstate, 0);
write_exp_elt_opcode (pstate, OP_AGGREGATE);
} }
else if (want_type || operation == top) else if (want_type || operation == top)
{ result.reset (new type_operation (type));
write_exp_elt_opcode (pstate, OP_TYPE);
write_exp_elt_type (pstate, type);
write_exp_elt_opcode (pstate, OP_TYPE);
}
else else
error (_("Found type '%s', which can't be " error (_("Found type '%s', which can't be "
"evaluated in this context"), "evaluated in this context"),
varname); varname);
} }
return result;
} }
break;
case OP_AGGREGATE: case OP_AGGREGATE:
{ {
int length;
rust_set_vector *fields = operation->right.field_inits; rust_set_vector *fields = operation->right.field_inits;
struct type *type; struct type *type;
const char *name; const char *name;
length = 0; operation_up others;
std::vector<std::pair<std::string, operation_up>> field_v;
for (const set_field &init : *fields) for (const set_field &init : *fields)
{ {
if (init.name.ptr != NULL) operation_up expr = convert_ast_to_expression (init.init, top);
{
write_exp_elt_opcode (pstate, OP_NAME);
write_exp_string (pstate, init.name);
write_exp_elt_opcode (pstate, OP_NAME);
++length;
}
convert_ast_to_expression (init.init, top);
++length;
if (init.name.ptr == NULL) if (init.name.ptr == NULL)
{ others = std::move (expr);
/* This is handled differently from Ada in our else
evaluator. */ field_v.emplace_back (init.name.ptr, std::move (expr));
write_exp_elt_opcode (pstate, OP_OTHERS);
}
} }
name = convert_name (operation->left.op); name = convert_name (operation->left.op);
@ -2475,34 +2489,29 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
|| rust_tuple_struct_type_p (type)) || rust_tuple_struct_type_p (type))
error (_("Struct expression applied to non-struct type")); error (_("Struct expression applied to non-struct type"));
write_exp_elt_opcode (pstate, OP_AGGREGATE); return operation_up
write_exp_elt_type (pstate, type); (new rust_aggregate_operation (type, std::move (others),
write_exp_elt_longcst (pstate, length); std::move (field_v)));
write_exp_elt_opcode (pstate, OP_AGGREGATE);
} }
break;
case OP_STRING: case OP_STRING:
{ return (operation_up
write_exp_elt_opcode (pstate, OP_STRING); (new string_operation (::copy_name (operation->left.sval))));
write_exp_string (pstate, operation->left.sval);
write_exp_elt_opcode (pstate, OP_STRING);
}
break;
case OP_RANGE: case OP_RANGE:
{ {
enum range_flag kind = (RANGE_HIGH_BOUND_DEFAULT enum range_flag kind = (RANGE_HIGH_BOUND_DEFAULT
| RANGE_LOW_BOUND_DEFAULT); | RANGE_LOW_BOUND_DEFAULT);
operation_up lhs, rhs;
if (operation->left.op != NULL) if (operation->left.op != NULL)
{ {
convert_ast_to_expression (operation->left.op, top); lhs = convert_ast_to_expression (operation->left.op, top);
kind &= ~RANGE_LOW_BOUND_DEFAULT; kind &= ~RANGE_LOW_BOUND_DEFAULT;
} }
if (operation->right.op != NULL) if (operation->right.op != NULL)
{ {
convert_ast_to_expression (operation->right.op, top); rhs = convert_ast_to_expression (operation->right.op, top);
if (kind == (RANGE_HIGH_BOUND_DEFAULT | RANGE_LOW_BOUND_DEFAULT)) if (kind == (RANGE_HIGH_BOUND_DEFAULT | RANGE_LOW_BOUND_DEFAULT))
{ {
kind = RANGE_LOW_BOUND_DEFAULT; kind = RANGE_LOW_BOUND_DEFAULT;
@ -2524,11 +2533,10 @@ rust_parser::convert_ast_to_expression (const struct rust_op *operation,
gdb_assert (!operation->inclusive); gdb_assert (!operation->inclusive);
} }
write_exp_elt_opcode (pstate, OP_RANGE); return operation_up (new rust_range_operation (kind,
write_exp_elt_longcst (pstate, kind); std::move (lhs),
write_exp_elt_opcode (pstate, OP_RANGE); std::move (rhs)));
} }
break;
default: default:
gdb_assert_not_reached ("unhandled opcode in convert_ast_to_expression"); gdb_assert_not_reached ("unhandled opcode in convert_ast_to_expression");
@ -2551,7 +2559,11 @@ rust_language::parser (struct parser_state *state) const
result = rustyyparse (&parser); result = rustyyparse (&parser);
if (!result || (state->parse_completion && parser.rust_ast != NULL)) if (!result || (state->parse_completion && parser.rust_ast != NULL))
parser.convert_ast_to_expression (parser.rust_ast, parser.rust_ast); {
expr::operation_up op
= parser.convert_ast_to_expression (parser.rust_ast, parser.rust_ast);
state->set_operation (std::move (op));
}
return result; return result;
} }
@ -2840,6 +2852,30 @@ _initialize_rust_exp ()
error. */ error. */
gdb_assert (code == 0); gdb_assert (code == 0);
using namespace expr;
maker_map[BINOP_SUBSCRIPT] = make_operation<rust_subscript_operation>;
maker_map[BINOP_MUL] = make_operation<mul_operation>;
maker_map[BINOP_REPEAT] = make_operation<repeat_operation>;
maker_map[BINOP_DIV] = make_operation<div_operation>;
maker_map[BINOP_REM] = make_operation<rem_operation>;
maker_map[BINOP_LESS] = make_operation<less_operation>;
maker_map[BINOP_GTR] = make_operation<gtr_operation>;
maker_map[BINOP_BITWISE_AND] = make_operation<bitwise_and_operation>;
maker_map[BINOP_BITWISE_IOR] = make_operation<bitwise_ior_operation>;
maker_map[BINOP_BITWISE_XOR] = make_operation<bitwise_xor_operation>;
maker_map[BINOP_ADD] = make_operation<add_operation>;
maker_map[BINOP_SUB] = make_operation<sub_operation>;
maker_map[BINOP_LOGICAL_OR] = make_operation<logical_or_operation>;
maker_map[BINOP_LOGICAL_AND] = make_operation<logical_and_operation>;
maker_map[BINOP_EQUAL] = make_operation<equal_operation>;
maker_map[BINOP_NOTEQUAL] = make_operation<notequal_operation>;
maker_map[BINOP_LEQ] = make_operation<leq_operation>;
maker_map[BINOP_GEQ] = make_operation<geq_operation>;
maker_map[BINOP_LSH] = make_operation<lsh_operation>;
maker_map[BINOP_RSH] = make_operation<rsh_operation>;
maker_map[BINOP_ASSIGN] = make_operation<assign_operation>;
maker_map[OP_RUST_ARRAY] = make_operation<rust_array_operation>;
#if GDB_SELF_TEST #if GDB_SELF_TEST
selftests::register_test ("rust-lex", rust_lex_tests); selftests::register_test ("rust-lex", rust_lex_tests);
#endif #endif