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.
This commit is contained in:
Andrew Burgess
2020-11-13 18:27:42 +00:00
parent 758cb81029
commit 9dd02fc063
5 changed files with 135 additions and 4 deletions

View File

@ -1,3 +1,13 @@
2020-11-14 Andrew Burgess <andrew.burgess@embecosm.com>
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 <tom@tromey.com>
* infrun.c (fetch_inferior_event): Use "bool" for should_stop.

View File

@ -149,6 +149,7 @@ static int parse_number (struct parser_state *, const char *, int,
%token <lval> BOOLEAN_LITERAL
%token <ssym> NAME
%token <tsym> TYPENAME
%token <voidval> COMPLETE
%type <sval> name
%type <ssym> 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;

View File

@ -1,3 +1,9 @@
2020-11-14 Andrew Burgess <andrew.burgess@embecosm.com>
PR cli/26879
* gdb.fortran/completion.exp: New file.
* gdb.fortran/completion.f90: New file.
2020-11-12 Joseph Myers <joseph@codesourcery.com>
* lib/gdb.exp (gdb_file_cmd): Check for case where $arg.exe exists

View File

@ -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 <http://www.gnu.org/licenses/> .
# 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"

View File

@ -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 <http://www.gnu.org/licenses/>.
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