Skip to content

Commit

Permalink
Parsing for signature in attribute name. Fixes #892
Browse files Browse the repository at this point in the history
  • Loading branch information
nickg committed May 19, 2024
1 parent 63befc0 commit 4a567f2
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 23 deletions.
2 changes: 2 additions & 0 deletions src/lexer.l
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ UNION ?i:union
<*>"=" { TOKEN(tEQ); }
<*>"#" { TOKEN(tHASH); }
<*>"~" { TOKEN(tTILDE); }
<*>"[[" { TOKEN(t2LSQUARE); }
<*>"]]" { TOKEN(t2RSQUARE); }

<INITIAL,PSL>"!" { TOKEN(tBAR); }
<VLOG>"!" { TOKEN(tBANG); }
Expand Down
54 changes: 33 additions & 21 deletions src/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1530,7 +1530,7 @@ static tree_t implicit_dereference(tree_t t)
return all;
}

static type_t prefix_type(tree_t prefix)
static type_t prefix_type(tree_t prefix, type_t signature)
{
if (scope_formal_kind(nametab) == F_SUBPROGRAM)
return NULL;
Expand All @@ -1554,7 +1554,7 @@ static type_t prefix_type(tree_t prefix)
if (tree_has_ref(ref) && !class_has_type(class_of(tree_ref(ref))))
return NULL;

return solve_types(nametab, prefix, NULL);
return solve_types(nametab, prefix, signature);
}

static bool is_range_expr(tree_t t)
Expand Down Expand Up @@ -2980,7 +2980,7 @@ static tree_t p_slice_name(tree_t prefix, tree_t head)

EXTEND("slice name");

type_t type = prefix_type(prefix);
type_t type = prefix_type(prefix, NULL);

if (type != NULL && type_is_access(type)) {
prefix = implicit_dereference(prefix);
Expand Down Expand Up @@ -3241,6 +3241,10 @@ static tree_t p_attribute_name(tree_t prefix)

EXTEND("attribute name");

type_t signature = NULL;
if (peek() == tLSQUARE)
signature = p_signature();

consume(tTICK);

attr_kind_t kind;
Expand Down Expand Up @@ -3272,7 +3276,23 @@ static tree_t p_attribute_name(tree_t prefix)
id = error_marker();
}

type_t type = prefix_type(prefix);
type_t type = prefix_type(prefix, signature);

if (signature != NULL) {
bool valid_signature = false;
if (type == NULL)
valid_signature = false;
else if (type_is_subprogram(type))
valid_signature = true;
else if (class_of(prefix) == C_LITERAL && type_is_enum(type))
valid_signature = true;
else if (type_is_none(type))
valid_signature = true; // Prevent cascading errors

if (!valid_signature)
parse_error(CURRENT_LOC, "prefix of attribute name with signature "
"does not denote a subprogram or enumeration literal");
}

if (type != NULL && type_kind(type) == T_INCOMPLETE) {
type = resolve_type(nametab, type);
Expand Down Expand Up @@ -3476,7 +3496,7 @@ static tree_t p_indexed_name(tree_t prefix, tree_t head)

EXTEND("indexed name");

type_t type = prefix_type(prefix);
type_t type = prefix_type(prefix, NULL);

if (type != NULL && type_is_access(type)) {
prefix = implicit_dereference(prefix);
Expand Down Expand Up @@ -4400,7 +4420,9 @@ static tree_t p_primary(tree_t head)
case tID:
{
tree_t expr = p_name(0);
if (tree_kind(expr) == T_PROT_REF)
if (peek() == tLSQUARE)
return p_attribute_name(expr);
else if (tree_kind(expr) == T_PROT_REF)
return p_function_call(tree_ident(expr), tree_value(expr));
else
return expr;
Expand Down Expand Up @@ -11577,19 +11599,14 @@ static psl_node_t p_psl_repeat_scheme(void)

static tree_t p_psl_proc_block(void)
{
// TODO: PSL LRM does not define "[[" and "]]" as token, thus we keep it as two
// consecutive square brace tokens (possibly split by space). However, all examples
// and grammar description in the PSL LRM never puts spae between these two.
consume(tLSQUARE);
consume(tLSQUARE);
consume(t2LSQUARE);

tree_t b = tree_new(T_BLOCK);
tree_set_loc(b, CURRENT_LOC);

scan_as_vhdl();

while (peek() != tRSQUARE && peek_nth(2) != tRSQUARE) {

while (not_at_token(t2RSQUARE)) {
if (scan(tSIGNAL, tTYPE, tSUBTYPE, tFILE, tCONSTANT, tFUNCTION, tIMPURE,
tPURE, tPROCEDURE, tALIAS, tATTRIBUTE, tFOR, tCOMPONENT, tUSE,
tSHARED, tDISCONNECT, tGROUP, tPACKAGE))
Expand All @@ -11600,9 +11617,7 @@ static tree_t p_psl_proc_block(void)

scan_as_psl();

consume(tRSQUARE);
consume(tRSQUARE);

consume(t2RSQUARE);
return b;
}

Expand Down Expand Up @@ -11843,12 +11858,9 @@ static psl_node_t p_psl_sequence(void)
// repeatitions shall be treated as if braces were present. Recurse
// and place the so-far parsed SERE as operand of new SERE. Similarly,
// this is valid also for Proc_Block
while (scan(tPLUSRPT, tTIMESRPT) ||
(peek() == tLSQUARE && peek_nth(2) == tLSQUARE)) {

while (scan(tPLUSRPT, tTIMESRPT, t2LSQUARE)) {
if (psl_kind(p) == P_HDL_EXPR ||
psl_has_repeat(p) ||
(peek() == tLSQUARE && peek_nth(2) == tLSQUARE)) {
psl_has_repeat(p) || peek() == t2LSQUARE) {
psl_node_t new = psl_new(P_SERE);
psl_add_operand(new, p);
p = new;
Expand Down
4 changes: 2 additions & 2 deletions src/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,9 @@ const char *token_str(token_t tok)
"bit", "bitvector", "numeric", "string", "[*", "[+]", "[=", "[->",
"&&", "within", "system task", "view", "private", "prev", "stable",
"rose", "fell", "ended", "nondet", "nondetv", "union", "translate on",
"translate off", "until!", "until_", "until_!", "`timescale"
"translate off", "until!", "until_", "until_!", "`timescale",
"supply0", "supply1", "pulldown", "pullup", "===", "!==", "==", "!=",
"(*", "*)", "number",
"(*", "*)", "number", "forever", "[[", "]]",
};

if (tok >= 200 && tok - 200 < ARRAY_LEN(token_strs))
Expand Down
2 changes: 2 additions & 0 deletions src/scan.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,5 +305,7 @@ bool is_scanned_as_psl(void);
#define tATTREND 409
#define tNUMBER 410
#define tFOREVER 411
#define t2LSQUARE 412
#define t2RSQUARE 413

#endif // _SCAN_H
30 changes: 30 additions & 0 deletions test/parse/issue892.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
entity issue892 is
end entity;

architecture test of issue892 is
function foo (x : integer) return boolean is
begin
return true;
end function;

function foo (y : bit) return string is
begin
return "hello";
end function;

type my_enum is ('1', '2');

attribute test : string;
attribute test of '1' [return my_enum] : literal is "hello";
begin

p: process is
begin
report foo [integer return boolean]'instance_name; -- OK
report foo [bit return string]'instance_name; -- OK
report p [integer return bit]'instance_name; -- Error
report '1' [return my_enum]'test; -- OK
wait;
end process;

end architecture;
27 changes: 27 additions & 0 deletions test/test_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -6355,6 +6355,32 @@ START_TEST(test_error12)
}
END_TEST

START_TEST(test_issue892)
{
input_from_file(TESTDIR "/parse/issue892.vhd");

const error_t expect[] = {
{ 25, "prefix of attribute name with signature does not denote a "
"subprogram or enumeration literal" },
{ -1, NULL }
};
expect_errors(expect);

tree_t e = parse();
fail_if(e == NULL);
fail_unless(tree_kind(e) == T_ENTITY);
lib_put(lib_work(), e);

tree_t a = parse();
fail_if(a == NULL);
fail_unless(tree_kind(a) == T_ARCH);

fail_unless(parse() == NULL);

check_expected_errors();
}
END_TEST

Suite *get_parse_tests(void)
{
Suite *s = suite_create("parse");
Expand Down Expand Up @@ -6497,6 +6523,7 @@ Suite *get_parse_tests(void)
tcase_add_test(tc_core, test_issue875);
tcase_add_test(tc_core, test_error11);
tcase_add_test(tc_core, test_error12);
tcase_add_test(tc_core, test_issue892);
suite_add_tcase(s, tc_core);

return s;
Expand Down

0 comments on commit 4a567f2

Please sign in to comment.