From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2126) id CAE72385840C; Mon, 4 Apr 2022 18:50:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org CAE72385840C Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Tom Tromey To: gdb-cvs@sourceware.org Subject: [binutils-gdb] Implement completion for Ada attributes X-Act-Checkin: binutils-gdb X-Git-Author: Tom Tromey X-Git-Refname: refs/heads/master X-Git-Oldrev: 1e237aba2216f89b9a4b3235ad8d09d1b1b8f039 X-Git-Newrev: c66ed94ae961c19b0d3028489d00a2df5a949aac Message-Id: <20220404185040.CAE72385840C@sourceware.org> Date: Mon, 4 Apr 2022 18:50:40 +0000 (GMT) X-BeenThere: gdb-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Apr 2022 18:50:40 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Dc66ed94ae961= c19b0d3028489d00a2df5a949aac commit c66ed94ae961c19b0d3028489d00a2df5a949aac Author: Tom Tromey Date: Tue Feb 22 11:18:01 2022 -0700 Implement completion for Ada attributes =20 This adds a completer for Ada attributes. Some work in the lexer is required in order to match end-of-input correctly, as flex does not have a general-purpose way of doing this. (The approach taken here is recommended in the flex manual.) Diff: --- gdb/ada-exp.y | 31 +++++++++++++- gdb/ada-lex.l | 71 ++++++++++++++++++++++++++++-= ---- gdb/parser-defs.h | 8 ++++ gdb/testsuite/gdb.ada/formatted_ref.exp | 5 +++ 4 files changed, 103 insertions(+), 12 deletions(-) diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y index ebf3925b98c..204e77af6ca 100644 --- a/gdb/ada-exp.y +++ b/gdb/ada-exp.y @@ -393,6 +393,30 @@ pop_associations (int n) return result; } =20 +/* Expression completer for attributes. */ +struct ada_tick_completer : public expr_completion_base +{ + explicit ada_tick_completer (std::string &&name) + : m_name (std::move (name)) + { + } + + bool complete (struct expression *exp, + completion_tracker &tracker) override; + +private: + + std::string m_name; +}; + +/* Make a new ada_tick_completer and wrap it in a unique pointer. */ +static std::unique_ptr +make_tick_completer (struct stoken tok) +{ + return (std::unique_ptr + (new ada_tick_completer (std::string (tok.ptr, tok.length)))); +} + %} =20 %union @@ -420,7 +444,7 @@ pop_associations (int n) %token FLOAT %token TRUEKEYWORD FALSEKEYWORD %token COLONCOLON -%token STRING NAME DOT_ID=20 +%token STRING NAME DOT_ID TICK_COMPLETE %type block %type arglist tick_arglist =20 @@ -449,6 +473,7 @@ pop_associations (int n) %right TICK_ACCESS TICK_ADDRESS TICK_FIRST TICK_LAST TICK_LENGTH %right TICK_MAX TICK_MIN TICK_MODULUS %right TICK_POS TICK_RANGE TICK_SIZE TICK_TAG TICK_VAL +%right TICK_COMPLETE /* The following are right-associative only so that reductions at this precedence have lower precedence than '.' and '('. The syntax still forces a.b.c, e.g., to be LEFT-associated. */ @@ -784,6 +809,10 @@ primary : primary TICK_ACCESS { ada_addrof (); } | primary TICK_ADDRESS { ada_addrof (type_system_address (pstate)); } + | primary TICK_COMPLETE + { + pstate->mark_completion (make_tick_completer ($2)); + } | primary TICK_FIRST tick_arglist { operation_up arg =3D ada_pop (); diff --git a/gdb/ada-lex.l b/gdb/ada-lex.l index c6ce1aec53a..6c32a9bd002 100644 --- a/gdb/ada-lex.l +++ b/gdb/ada-lex.l @@ -39,6 +39,11 @@ OPER ([-+*/=3D<>&]|"<=3D"|">=3D"|"**"|"/=3D"|"and"|"o= r"|"xor"|"not"|"mod"|"rem"|"abs" EXP (e[+-]{NUM10}) POSEXP (e"+"?{NUM10}) =20 +/* This must agree with COMPLETION_CHAR below. See the comment there + for the explanation. */ +COMPLETE "\001" +NOT_COMPLETE [^\001] + %{ =20 #include "diagnostics.h" @@ -73,16 +78,35 @@ static void rewind_to_char (int); Defining YY_NO_INPUT comments it out. */ #define YY_NO_INPUT =20 +/* When completing, we'll return a special character at the end of the + input, to signal the completion position to the lexer. This is + done because flex does not have a generally useful way to detect + EOF in a pattern. This variable records whether the special + character has been emitted. */ +static bool returned_complete =3D false; + +/* The character we use to represent the completion point. */ +#define COMPLETE_CHAR '\001' + #undef YY_INPUT -#define YY_INPUT(BUF, RESULT, MAX_SIZE) \ - if ( *pstate->lexptr =3D=3D '\000' ) \ - (RESULT) =3D YY_NULL; \ - else \ - { \ - *(BUF) =3D *pstate->lexptr; \ - (RESULT) =3D 1; \ - pstate->lexptr +=3D 1; \ - } +#define YY_INPUT(BUF, RESULT, MAX_SIZE) \ + if ( *pstate->lexptr =3D=3D '\000' ) \ + { \ + if (pstate->parse_completion && !returned_complete) \ + { \ + returned_complete =3D true; \ + *(BUF) =3D COMPLETE_CHAR; \ + (RESULT) =3D 1; \ + } \ + else \ + (RESULT) =3D YY_NULL; \ + } \ + else \ + { \ + *(BUF) =3D *pstate->lexptr =3D=3D COMPLETE_CHAR ? ' ' : *pstate->lex= ptr; \ + (RESULT) =3D 1; \ + pstate->lexptr +=3D 1; \ + } =20 static int find_dot_all (const char *); =20 @@ -227,7 +251,7 @@ false { return FALSEKEYWORD; } =20 /* ATTRIBUTES */ =20 -{TICK}[a-z][a-z_]+ { BEGIN INITIAL; return processAttribute (yytext); } +{TICK}([a-z][a-z_]*)?{COMPLETE}? { BEGIN INITIAL; return processAttribute = (yytext); } =20 /* PUNCTUATION */ =20 @@ -239,7 +263,7 @@ false { return FALSEKEYWORD; } "<=3D" { return LEQ; } ">=3D" { return GEQ; } =20 -"'" { BEGIN INITIAL; return '\''; } +"'"/{NOT_COMPLETE} { BEGIN INITIAL; return '\''; } =20 [-&*+./:<>=3D|;\[\]] { return yytext[0]; } =20 @@ -320,6 +344,7 @@ lexer_init (FILE *inp) { BEGIN INITIAL; paren_depth =3D 0; + returned_complete =3D false; yyrestart (inp); } =20 @@ -668,6 +693,16 @@ processAttribute (const char *str) while (isspace (*str)) ++str; =20 + int len =3D strlen (str); + if (len > 0 && str[len - 1] =3D=3D COMPLETE_CHAR) + { + /* This is enforced by YY_INPUT. */ + gdb_assert (pstate->parse_completion); + yylval.sval.ptr =3D obstack_strndup (&temp_parse_space, str, len - 1= ); + yylval.sval.length =3D len - 1; + return TICK_COMPLETE; + } + for (const auto &item : attributes) if (strcasecmp (str, item.name) =3D=3D 0) return item.code; @@ -687,6 +722,20 @@ processAttribute (const char *str) return *found; } =20 +bool +ada_tick_completer::complete (struct expression *exp, + completion_tracker &tracker) +{ + completion_list output; + for (const auto &item : attributes) + { + if (strncasecmp (item.name, m_name.c_str (), m_name.length ()) =3D= =3D 0) + output.emplace_back (xstrdup (item.name)); + } + tracker.add_completions (std::move (output)); + return true; +} + /* Back up lexptr by yyleng and then to the rightmost occurrence of character CH, case-folded (there must be one). WARNING: since lexptr points to the next input character that Flex has not yet diff --git a/gdb/parser-defs.h b/gdb/parser-defs.h index 71381b1a725..3be7d6c839f 100644 --- a/gdb/parser-defs.h +++ b/gdb/parser-defs.h @@ -195,6 +195,14 @@ struct parser_state : public expr_builder =20 void mark_completion_tag (enum type_code tag, const char *ptr, int lengt= h); =20 + /* Mark for completion, using an arbitrary completer. */ + + void mark_completion (std::unique_ptr completer) + { + gdb_assert (m_completion_state =3D=3D nullptr); + m_completion_state =3D std::move (completer); + } + /* Push an operation on the stack. */ void push (expr::operation_up &&op) { diff --git a/gdb/testsuite/gdb.ada/formatted_ref.exp b/gdb/testsuite/gdb.ad= a/formatted_ref.exp index 882dbf17725..19a32658d98 100644 --- a/gdb/testsuite/gdb.ada/formatted_ref.exp +++ b/gdb/testsuite/gdb.ada/formatted_ref.exp @@ -82,6 +82,11 @@ proc test_p_x_addr { var addr } { } } } + + gdb_test "complete print/x $var'unres" "print/x $var'unrestricted_acce= ss" + gdb_test_no_output "complete print/x $var'abcd" + gdb_test "complete print $var'f" "print $var'first" + return 0 }