Implement completion for Ada attributes
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.)
This commit is contained in:
parent
1e237aba22
commit
c66ed94ae9
4 changed files with 103 additions and 12 deletions
|
@ -393,6 +393,30 @@ pop_associations (int n)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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<expr_completion_base>
|
||||||
|
make_tick_completer (struct stoken tok)
|
||||||
|
{
|
||||||
|
return (std::unique_ptr<expr_completion_base>
|
||||||
|
(new ada_tick_completer (std::string (tok.ptr, tok.length))));
|
||||||
|
}
|
||||||
|
|
||||||
%}
|
%}
|
||||||
|
|
||||||
%union
|
%union
|
||||||
|
@ -420,7 +444,7 @@ pop_associations (int n)
|
||||||
%token <typed_val_float> FLOAT
|
%token <typed_val_float> FLOAT
|
||||||
%token TRUEKEYWORD FALSEKEYWORD
|
%token TRUEKEYWORD FALSEKEYWORD
|
||||||
%token COLONCOLON
|
%token COLONCOLON
|
||||||
%token <sval> STRING NAME DOT_ID
|
%token <sval> STRING NAME DOT_ID TICK_COMPLETE
|
||||||
%type <bval> block
|
%type <bval> block
|
||||||
%type <lval> arglist tick_arglist
|
%type <lval> arglist tick_arglist
|
||||||
|
|
||||||
|
@ -449,6 +473,7 @@ pop_associations (int n)
|
||||||
%right TICK_ACCESS TICK_ADDRESS TICK_FIRST TICK_LAST TICK_LENGTH
|
%right TICK_ACCESS TICK_ADDRESS TICK_FIRST TICK_LAST TICK_LENGTH
|
||||||
%right TICK_MAX TICK_MIN TICK_MODULUS
|
%right TICK_MAX TICK_MIN TICK_MODULUS
|
||||||
%right TICK_POS TICK_RANGE TICK_SIZE TICK_TAG TICK_VAL
|
%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
|
/* The following are right-associative only so that reductions at this
|
||||||
precedence have lower precedence than '.' and '('. The syntax still
|
precedence have lower precedence than '.' and '('. The syntax still
|
||||||
forces a.b.c, e.g., to be LEFT-associated. */
|
forces a.b.c, e.g., to be LEFT-associated. */
|
||||||
|
@ -784,6 +809,10 @@ primary : primary TICK_ACCESS
|
||||||
{ ada_addrof (); }
|
{ ada_addrof (); }
|
||||||
| primary TICK_ADDRESS
|
| primary TICK_ADDRESS
|
||||||
{ ada_addrof (type_system_address (pstate)); }
|
{ ada_addrof (type_system_address (pstate)); }
|
||||||
|
| primary TICK_COMPLETE
|
||||||
|
{
|
||||||
|
pstate->mark_completion (make_tick_completer ($2));
|
||||||
|
}
|
||||||
| primary TICK_FIRST tick_arglist
|
| primary TICK_FIRST tick_arglist
|
||||||
{
|
{
|
||||||
operation_up arg = ada_pop ();
|
operation_up arg = ada_pop ();
|
||||||
|
|
|
@ -39,6 +39,11 @@ OPER ([-+*/=<>&]|"<="|">="|"**"|"/="|"and"|"or"|"xor"|"not"|"mod"|"rem"|"abs"
|
||||||
EXP (e[+-]{NUM10})
|
EXP (e[+-]{NUM10})
|
||||||
POSEXP (e"+"?{NUM10})
|
POSEXP (e"+"?{NUM10})
|
||||||
|
|
||||||
|
/* This must agree with COMPLETION_CHAR below. See the comment there
|
||||||
|
for the explanation. */
|
||||||
|
COMPLETE "\001"
|
||||||
|
NOT_COMPLETE [^\001]
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|
||||||
#include "diagnostics.h"
|
#include "diagnostics.h"
|
||||||
|
@ -73,16 +78,35 @@ static void rewind_to_char (int);
|
||||||
Defining YY_NO_INPUT comments it out. */
|
Defining YY_NO_INPUT comments it out. */
|
||||||
#define YY_NO_INPUT
|
#define YY_NO_INPUT
|
||||||
|
|
||||||
|
/* 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 = false;
|
||||||
|
|
||||||
|
/* The character we use to represent the completion point. */
|
||||||
|
#define COMPLETE_CHAR '\001'
|
||||||
|
|
||||||
#undef YY_INPUT
|
#undef YY_INPUT
|
||||||
#define YY_INPUT(BUF, RESULT, MAX_SIZE) \
|
#define YY_INPUT(BUF, RESULT, MAX_SIZE) \
|
||||||
if ( *pstate->lexptr == '\000' ) \
|
if ( *pstate->lexptr == '\000' ) \
|
||||||
(RESULT) = YY_NULL; \
|
{ \
|
||||||
else \
|
if (pstate->parse_completion && !returned_complete) \
|
||||||
{ \
|
{ \
|
||||||
*(BUF) = *pstate->lexptr; \
|
returned_complete = true; \
|
||||||
(RESULT) = 1; \
|
*(BUF) = COMPLETE_CHAR; \
|
||||||
pstate->lexptr += 1; \
|
(RESULT) = 1; \
|
||||||
}
|
} \
|
||||||
|
else \
|
||||||
|
(RESULT) = YY_NULL; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
*(BUF) = *pstate->lexptr == COMPLETE_CHAR ? ' ' : *pstate->lexptr; \
|
||||||
|
(RESULT) = 1; \
|
||||||
|
pstate->lexptr += 1; \
|
||||||
|
}
|
||||||
|
|
||||||
static int find_dot_all (const char *);
|
static int find_dot_all (const char *);
|
||||||
|
|
||||||
|
@ -227,7 +251,7 @@ false { return FALSEKEYWORD; }
|
||||||
|
|
||||||
/* ATTRIBUTES */
|
/* ATTRIBUTES */
|
||||||
|
|
||||||
{TICK}[a-z][a-z_]+ { BEGIN INITIAL; return processAttribute (yytext); }
|
{TICK}([a-z][a-z_]*)?{COMPLETE}? { BEGIN INITIAL; return processAttribute (yytext); }
|
||||||
|
|
||||||
/* PUNCTUATION */
|
/* PUNCTUATION */
|
||||||
|
|
||||||
|
@ -239,7 +263,7 @@ false { return FALSEKEYWORD; }
|
||||||
"<=" { return LEQ; }
|
"<=" { return LEQ; }
|
||||||
">=" { return GEQ; }
|
">=" { return GEQ; }
|
||||||
|
|
||||||
<BEFORE_QUAL_QUOTE>"'" { BEGIN INITIAL; return '\''; }
|
<BEFORE_QUAL_QUOTE>"'"/{NOT_COMPLETE} { BEGIN INITIAL; return '\''; }
|
||||||
|
|
||||||
[-&*+./:<>=|;\[\]] { return yytext[0]; }
|
[-&*+./:<>=|;\[\]] { return yytext[0]; }
|
||||||
|
|
||||||
|
@ -320,6 +344,7 @@ lexer_init (FILE *inp)
|
||||||
{
|
{
|
||||||
BEGIN INITIAL;
|
BEGIN INITIAL;
|
||||||
paren_depth = 0;
|
paren_depth = 0;
|
||||||
|
returned_complete = false;
|
||||||
yyrestart (inp);
|
yyrestart (inp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,6 +693,16 @@ processAttribute (const char *str)
|
||||||
while (isspace (*str))
|
while (isspace (*str))
|
||||||
++str;
|
++str;
|
||||||
|
|
||||||
|
int len = strlen (str);
|
||||||
|
if (len > 0 && str[len - 1] == COMPLETE_CHAR)
|
||||||
|
{
|
||||||
|
/* This is enforced by YY_INPUT. */
|
||||||
|
gdb_assert (pstate->parse_completion);
|
||||||
|
yylval.sval.ptr = obstack_strndup (&temp_parse_space, str, len - 1);
|
||||||
|
yylval.sval.length = len - 1;
|
||||||
|
return TICK_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto &item : attributes)
|
for (const auto &item : attributes)
|
||||||
if (strcasecmp (str, item.name) == 0)
|
if (strcasecmp (str, item.name) == 0)
|
||||||
return item.code;
|
return item.code;
|
||||||
|
@ -687,6 +722,20 @@ processAttribute (const char *str)
|
||||||
return *found;
|
return *found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 ()) == 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
|
/* Back up lexptr by yyleng and then to the rightmost occurrence of
|
||||||
character CH, case-folded (there must be one). WARNING: since
|
character CH, case-folded (there must be one). WARNING: since
|
||||||
lexptr points to the next input character that Flex has not yet
|
lexptr points to the next input character that Flex has not yet
|
||||||
|
|
|
@ -195,6 +195,14 @@ struct parser_state : public expr_builder
|
||||||
|
|
||||||
void mark_completion_tag (enum type_code tag, const char *ptr, int length);
|
void mark_completion_tag (enum type_code tag, const char *ptr, int length);
|
||||||
|
|
||||||
|
/* Mark for completion, using an arbitrary completer. */
|
||||||
|
|
||||||
|
void mark_completion (std::unique_ptr<expr_completion_base> completer)
|
||||||
|
{
|
||||||
|
gdb_assert (m_completion_state == nullptr);
|
||||||
|
m_completion_state = std::move (completer);
|
||||||
|
}
|
||||||
|
|
||||||
/* Push an operation on the stack. */
|
/* Push an operation on the stack. */
|
||||||
void push (expr::operation_up &&op)
|
void push (expr::operation_up &&op)
|
||||||
{
|
{
|
||||||
|
|
|
@ -82,6 +82,11 @@ proc test_p_x_addr { var addr } {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gdb_test "complete print/x $var'unres" "print/x $var'unrestricted_access"
|
||||||
|
gdb_test_no_output "complete print/x $var'abcd"
|
||||||
|
gdb_test "complete print $var'f" "print $var'first"
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue