From: Andrew Burgess Date: Fri, 13 Nov 2020 18:27:42 +0000 (+0000) Subject: gdb: add tab completion of type field names for Fortran X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9dd02fc063284f59994c095ce525e1b8934b0dc1;p=binutils-gdb.git gdb: add tab completion of type field names for Fortran Add support for tab-completion on Fortran field names. Consider this test case: program test type my_type integer :: field_a integer :: other_field integer :: last_field end type my_type type(my_type) :: var print *, var end program test And the GDB session before this patch: (gdb) start ... (gdb) p var% <- Trigger TAB completion here. Display all 200 possibilities? (y or n) n (gdb) p var% And the GDB session with this patch: (gdb) start ... (gdb) p var% <- Trigger TAB completion here. field_a last_field other_field (gdb) p var% The implementation for this is basically copied from c-exp.y, I tweaked the parser patterns to be appropriate for Fortran, and it "just worked". gdb/ChangeLog: PR cli/26879 * f-exp.y (COMPLETE): New token. (exp): Two new rules for tab-completion. (saw_name_at_eof): New static global. (last_was_structop): Likewise. (yylex): Set new variables, and return COMPLETE token at the end of the input stream in some cases. gdb/testsuite/ChangeLog: PR cli/26879 * gdb.fortran/completion.exp: New file. * gdb.fortran/completion.f90: New file. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 69af942bc75..a70c5feaff1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2020-11-14 Andrew Burgess + + PR cli/26879 + * f-exp.y (COMPLETE): New token. + (exp): Two new rules for tab-completion. + (saw_name_at_eof): New static global. + (last_was_structop): Likewise. + (yylex): Set new variables, and return COMPLETE token at the end + of the input stream in some cases. + 2020-11-14 Tom Tromey * infrun.c (fetch_inferior_event): Use "bool" for should_stop. diff --git a/gdb/f-exp.y b/gdb/f-exp.y index 5e16678886b..edfbe0cd220 100644 --- a/gdb/f-exp.y +++ b/gdb/f-exp.y @@ -149,6 +149,7 @@ static int parse_number (struct parser_state *, const char *, int, %token BOOLEAN_LITERAL %token NAME %token TYPENAME +%token COMPLETE %type name %type name_not_typename @@ -374,6 +375,22 @@ exp : exp '%' name write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); } ; +exp : exp '%' name COMPLETE + { pstate->mark_struct_expression (); + write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); + write_exp_string (pstate, $3); + write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); } + ; + +exp : exp '%' COMPLETE + { struct stoken s; + pstate->mark_struct_expression (); + write_exp_elt_opcode (pstate, STRUCTOP_PTR); + s.ptr = ""; + s.length = 0; + write_exp_string (pstate, s); + write_exp_elt_opcode (pstate, STRUCTOP_PTR); } + /* Binary operators in order of decreasing precedence. */ exp : exp '@' exp @@ -1100,6 +1117,15 @@ match_string_literal (void) } } +/* This is set if a NAME token appeared at the very end of the input + string, with no whitespace separating the name from the EOF. This + is used only when parsing to do field name completion. */ +static bool saw_name_at_eof; + +/* This is set if the previously-returned token was a structure + operator '%'. */ +static bool last_was_structop; + /* Read one token, getting characters through lexptr. */ static int @@ -1109,7 +1135,10 @@ yylex (void) int namelen; unsigned int token; const char *tokstart; - + bool saw_structop = last_was_structop; + + last_was_structop = false; + retry: pstate->prev_lexptr = pstate->lexptr; @@ -1156,6 +1185,13 @@ yylex (void) switch (c = *tokstart) { case 0: + if (saw_name_at_eof) + { + saw_name_at_eof = false; + return COMPLETE; + } + else if (pstate->parse_completion && saw_structop) + return COMPLETE; return 0; case ' ': @@ -1257,12 +1293,14 @@ yylex (void) pstate->lexptr = p; return toktype; } - + + case '%': + last_was_structop = true; + /* Fall through. */ case '+': case '-': case '*': case '/': - case '%': case '|': case '&': case '^': @@ -1374,7 +1412,10 @@ yylex (void) return NAME_OR_INT; } } - + + if (pstate->parse_completion && *pstate->lexptr == '\0') + saw_name_at_eof = true; + /* Any other kind of symbol */ yylval.ssym.sym = result; yylval.ssym.is_a_field_of_this = false; @@ -1391,6 +1432,8 @@ f_language::parser (struct parser_state *par_state) const parser_debug); gdb_assert (par_state != NULL); pstate = par_state; + last_was_structop = false; + saw_name_at_eof = false; paren_depth = 0; struct type_stack stack; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index b1ca924c2f0..b1a8f8f4f0b 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2020-11-14 Andrew Burgess + + PR cli/26879 + * gdb.fortran/completion.exp: New file. + * gdb.fortran/completion.f90: New file. + 2020-11-12 Joseph Myers * lib/gdb.exp (gdb_file_cmd): Check for case where $arg.exe exists diff --git a/gdb/testsuite/gdb.fortran/completion.exp b/gdb/testsuite/gdb.fortran/completion.exp new file mode 100644 index 00000000000..1458799bf64 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/completion.exp @@ -0,0 +1,46 @@ +# Copyright 2020 Free Software Foundation, Inc. + +# 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 . + +# Test tab completion of Fortran type field names. + +if {[skip_fortran_tests]} { return -1 } + +standard_testfile ".f90" +load_lib fortran.exp +load_lib completion-support.exp + +if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} \ + {debug f90}]} { + return -1 +} + +if ![fortran_runto_main] { + untested "could not run to main" + return -1 +} + +test_gdb_complete_none "p var%x" +test_gdb_complete_multiple "p var%" "" "" { + "aa_field_1" + "aa_field_2" + "bb_field_3" +} + +test_gdb_complete_multiple "p var%" "aa" "_field_" { + "aa_field_1" + "aa_field_2" +} + +test_gdb_complete_unique "p var%b" "p var%bb_field_3" diff --git a/gdb/testsuite/gdb.fortran/completion.f90 b/gdb/testsuite/gdb.fortran/completion.f90 new file mode 100644 index 00000000000..605f783e494 --- /dev/null +++ b/gdb/testsuite/gdb.fortran/completion.f90 @@ -0,0 +1,26 @@ +! Copyright 2020 Free Software Foundation, Inc. +! +! 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 . + +program test + type some_type + integer :: aa_field_1 + integer :: aa_field_2 + integer :: bb_field_3 + end type some_type + + type(some_type) :: var + + print *, var +end program test