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:
parent
758cb81029
commit
9dd02fc063
5 changed files with 135 additions and 4 deletions
|
@ -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>
|
2020-11-14 Tom Tromey <tom@tromey.com>
|
||||||
|
|
||||||
* infrun.c (fetch_inferior_event): Use "bool" for should_stop.
|
* infrun.c (fetch_inferior_event): Use "bool" for should_stop.
|
||||||
|
|
51
gdb/f-exp.y
51
gdb/f-exp.y
|
@ -149,6 +149,7 @@ static int parse_number (struct parser_state *, const char *, int,
|
||||||
%token <lval> BOOLEAN_LITERAL
|
%token <lval> BOOLEAN_LITERAL
|
||||||
%token <ssym> NAME
|
%token <ssym> NAME
|
||||||
%token <tsym> TYPENAME
|
%token <tsym> TYPENAME
|
||||||
|
%token <voidval> COMPLETE
|
||||||
%type <sval> name
|
%type <sval> name
|
||||||
%type <ssym> name_not_typename
|
%type <ssym> name_not_typename
|
||||||
|
|
||||||
|
@ -374,6 +375,22 @@ exp : exp '%' name
|
||||||
write_exp_elt_opcode (pstate, STRUCTOP_STRUCT); }
|
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. */
|
/* Binary operators in order of decreasing precedence. */
|
||||||
|
|
||||||
exp : exp '@' exp
|
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. */
|
/* Read one token, getting characters through lexptr. */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1109,7 +1135,10 @@ yylex (void)
|
||||||
int namelen;
|
int namelen;
|
||||||
unsigned int token;
|
unsigned int token;
|
||||||
const char *tokstart;
|
const char *tokstart;
|
||||||
|
bool saw_structop = last_was_structop;
|
||||||
|
|
||||||
|
last_was_structop = false;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
|
|
||||||
pstate->prev_lexptr = pstate->lexptr;
|
pstate->prev_lexptr = pstate->lexptr;
|
||||||
|
@ -1156,6 +1185,13 @@ yylex (void)
|
||||||
switch (c = *tokstart)
|
switch (c = *tokstart)
|
||||||
{
|
{
|
||||||
case 0:
|
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;
|
return 0;
|
||||||
|
|
||||||
case ' ':
|
case ' ':
|
||||||
|
@ -1257,12 +1293,14 @@ yylex (void)
|
||||||
pstate->lexptr = p;
|
pstate->lexptr = p;
|
||||||
return toktype;
|
return toktype;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case '%':
|
||||||
|
last_was_structop = true;
|
||||||
|
/* Fall through. */
|
||||||
case '+':
|
case '+':
|
||||||
case '-':
|
case '-':
|
||||||
case '*':
|
case '*':
|
||||||
case '/':
|
case '/':
|
||||||
case '%':
|
|
||||||
case '|':
|
case '|':
|
||||||
case '&':
|
case '&':
|
||||||
case '^':
|
case '^':
|
||||||
|
@ -1374,7 +1412,10 @@ yylex (void)
|
||||||
return NAME_OR_INT;
|
return NAME_OR_INT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pstate->parse_completion && *pstate->lexptr == '\0')
|
||||||
|
saw_name_at_eof = true;
|
||||||
|
|
||||||
/* Any other kind of symbol */
|
/* Any other kind of symbol */
|
||||||
yylval.ssym.sym = result;
|
yylval.ssym.sym = result;
|
||||||
yylval.ssym.is_a_field_of_this = false;
|
yylval.ssym.is_a_field_of_this = false;
|
||||||
|
@ -1391,6 +1432,8 @@ f_language::parser (struct parser_state *par_state) const
|
||||||
parser_debug);
|
parser_debug);
|
||||||
gdb_assert (par_state != NULL);
|
gdb_assert (par_state != NULL);
|
||||||
pstate = par_state;
|
pstate = par_state;
|
||||||
|
last_was_structop = false;
|
||||||
|
saw_name_at_eof = false;
|
||||||
paren_depth = 0;
|
paren_depth = 0;
|
||||||
|
|
||||||
struct type_stack stack;
|
struct type_stack stack;
|
||||||
|
|
|
@ -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>
|
2020-11-12 Joseph Myers <joseph@codesourcery.com>
|
||||||
|
|
||||||
* lib/gdb.exp (gdb_file_cmd): Check for case where $arg.exe exists
|
* lib/gdb.exp (gdb_file_cmd): Check for case where $arg.exe exists
|
||||||
|
|
46
gdb/testsuite/gdb.fortran/completion.exp
Normal file
46
gdb/testsuite/gdb.fortran/completion.exp
Normal 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"
|
26
gdb/testsuite/gdb.fortran/completion.f90
Normal file
26
gdb/testsuite/gdb.fortran/completion.f90
Normal 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
|
Loading…
Add table
Add a link
Reference in a new issue