universal-ctags / ctags

A maintained ctags implementation
https://ctags.io
GNU General Public License v2.0
6.38k stars 617 forks source link

VHDL: adding process and instanced component kinds #2678

Open pidgeon777 opened 3 years ago

pidgeon777 commented 3 years ago

These are the VHDL kinds parsed in the latest implementation of ctags:

static kindDefinition VhdlKinds[] = {
    {true, 'c', "constant", "constant declarations"},
    {true, 't', "type", "type definitions"},
    {true, 'T', "subtype", "subtype definitions"},
    {true, 'r', "record", "record names"},
    {true, 'e', "entity", "entity declarations"},
    {false, 'C', "component", "component declarations"},
    {false, 'd', "prototype", "prototypes"},
    {true, 'f', "function", "function prototypes and declarations"},
    {true, 'p', "procedure", "procedure prototypes and declarations"},
    {true, 'P', "package", "package definitions"},
    {false, 'l', "local", "local definitions"}
};

https://github.com/universal-ctags/ctags/blob/master/parsers/vhdl.c

Please add three more kinds:

optional_label: process (optional sensitivity list)
    declarations
begin
    sequential statements
end process optional_label;

optional_label is the optional process label and should be reported as tag (e.g. kind = process). If missing, a random string (e.g. 4534_process) should be used as tag name instead. ctags' parsed anonymous structs in C can be considered as an example.

instance_label: component_name
    generic map (generic_association_list)
    port map (port_association_list);

instance_label is the mandatory component instantiation label and should be reported as tag (e.g. kind = component instance label). component_name is the instantiated component name and should be reported as tag as well (e.g. kind = component instance), so that the associated component/entity tags could be found.

masatake commented 3 years ago

I found an example in our test cases:

entity accumulator is port (
  a: in std_logic_vector(3 downto 0);
  clk, reset: in std_logic;
  accum: out std_logic_vector(3 downto 0)
  );
end accumulator;

architecture simple of accumulator is

signal accumL: unsigned(3 downto 0);

begin

  accumulate: process (clk, reset) begin
    if (reset = '1') then
      accumL <= "0000";
    elsif (clk'event and clk= '1') then
      accumL <= accumL + to_unsigned(a);
    end if;
  end process;

  accum <= std_logic_vector(accumL);

end simple;

Before talking about process, I have a question. I think "simple" should be tagged if we should make a tag for accumulate. Am I correct? In this case what "kind" should we use for "simple"?

pidgeon777 commented 3 years ago

Yes, simple should be tagged, too. Each VHDL entity has an architecture which defines the behaviour of the entity itself.

Thus, I would propose to add one more VHDL kind: a, for architecture bodies.

masatake commented 3 years ago

@pidgeon777, thank you.

masatake commented 3 years ago

2687 is a pull request to tag the architectures.

entity accumulator is port (
  a: in std_logic_vector(3 downto 0);
  clk, reset: in std_logic;
  accum: out std_logic_vector(3 downto 0)
  );
end accumulator;

I think a, clk, accum, accumL should be tagged, too. For tagging accumL, we should introduce "signal" kind. For tagging a, clk, accum, ~what kind we should introduce?~ I guess we should introduce "port" kind.

scope fields are not filled. So you cannot do any interesting things.

pidgeon777 commented 3 years ago

For tagging a, clk, accum, what kind we should introduce? I guess we should introduce "port" kind.

Yes, they should be tagged as well, eventually as port declarations:

http://www.vhdl.renerta.com/mobile/source/vhd00051.htm

For tagging accumL, we should introduce "signal" kind.

signal declarations would also be ok:

http://www.vhdl.renerta.com/source/vhd00064.htm

scope fields are not filled. So you cannot do any interesting things.

I didn't understand the above point.

However, we should not forget about generics, too:

http://www.vhdl.renerta.com/source/vhd00034.htm

Those are also really important in VHDL, and should thus be tagged, too.

masatake commented 3 years ago

Thank you.

scope field represents owner/owned or parent/child relationships. Client tools can make a "tree" from the fields.

I would like to show an example in C language.

input.c:

     1  struct point {
     2      int x, y;
     3  };
     4  int length (point *p0, point *p1)
     5  {
     6     int dx = p1->x - p0->x;
     7     int dy = p1->y - p0->y;
     8     return (int)sqrt((double)(dx*dx + dy*dy));
     9  }

ctags output:

% u-ctags --sort=no --fields=+KkZzSe-lf -n --kinds-C=+zl -o - input.c 
point   input.c 1;" kind:struct end:3
x   input.c 2;" kind:member scope:struct:point  typeref:typename:int    end:2
y   input.c 2;" kind:member scope:struct:point  typeref:typename:int    end:2
length  input.c 4;" kind:function   typeref:typename:int    signature:(point * p0,point * p1)   end:9
p0  input.c 4;" kind:parameter  scope:function:length   typeref:typename:point *
p1  input.c 4;" kind:parameter  scope:function:length   typeref:typename:point *
dx  input.c 6;" kind:local  scope:function:length   typeref:typename:int    end:6
dy  input.c 7;" kind:local  scope:function:length   typeref:typename:int    end:7

See scope: in the output.

Let's think about VHDL.

entity accumulator is port (
  a: in std_logic_vector(3 downto 0);
  clk, reset: in std_logic;
  accum: out std_logic_vector(3 downto 0)
  );
end accumulator;

The scope of a, clk, and accum may be: "scope:entity:accumulator". These ones are easy.

architecture simple of accumulator is

signal accumL: unsigned(3 downto 0);

begin
...

How about accumL? One of my ideas is scope:architecture:simple. This will be better than scope:entity:accumulator because accumulator may have multiple architectures.

masatake commented 3 years ago

VHDL: tag architectures #2687 is merged.

masatake commented 3 years ago

See also https://insights.sigasi.com/opinion/emacs/vhdl-emacs-mode-navigation-using-ctags-are-broken/ and https://stackoverflow.com/questions/16814436/vhdl-tags-not-efficient-in-vim-with-ctagstaglist .

masatake commented 3 years ago

Ports are tagged: https://github.com/universal-ctags/ctags/pull/2695 .

masatake commented 3 years ago

For tagging a, clk, accum, what kind we should introduce? I guess we should introduce "port" kind.

Yes, they should be tagged as well, eventually as port declarations:

Do you mean "port declaration" is better than "port" as the kind name for a, clk, accum? I made a pull request (#2695) for tagging ports. I used "port" as the name of kind. Am I going to wrong way?

pidgeon777 commented 3 years ago

Here I am again. I think ctags has a lot of potential for tagging HDL languages (VHDL, Verilog, SystemVerilog) even for code analysis/linting purposes, thus I'm more than happy to help.

Maybe it won't be possible for me to quickly reply on certain days, but I'll try to answer all of your questions as soon as I can.

Moreover, I have some interesting ideas to share later today, and I will also provide you with the answers you asked for.

masatake commented 3 years ago

Excellent!

masatake commented 3 years ago

@pidgeon777, Do you think "port" is bad kind name?

$ ./ctags --list-kinds=SystemVerilog
c  constants (define, parameter, specparam, enum values)
e  events
f  functions
m  modules
n  net data types
p  ports

I don't know well about languages for hardware. However, "port" is used in SystemVerilog. So I assume using the same name in VHDL may be o.k.

pidgeon777 commented 3 years ago

Hi @masatake, the list of VHDL kinds:

c  constant declarations
t  type definitions
T  subtype definitions
r  record names
e  entity declarations
C  component declarations [off]
d  prototypes [off]
f  function prototypes and declarations
p  procedure prototypes and declarations
P  package definitions
l  local definitions [off]

port could be ok, but if you want to maintain the same format used in those VHDL kinds, then I think one of the following could be more appropriate:

Still, I'm not so sure about the difference between definition and declaration in VHDL. A C++ case:

https://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration

Later this evening I'll try to answer the remaining questions you asked for, I already took some notes a few days ago.

masatake commented 3 years ago

I see. You are talking about "DESCRIPTION".

$ ./ctags --list-kinds-full=VHDL      
#LETTER NAME         ENABLED REFONLY NROLES MASTER DESCRIPTION
C       component    no      no      0      NONE   component declarations
P       package      yes     no      0      NONE   package definitions
T       subtype      yes     no      0      NONE   subtype definitions
a       architecture yes     no      0      NONE   architectures
c       constant     yes     no      0      NONE   constant declarations
d       prototype    no      no      0      NONE   prototypes
e       entity       yes     no      0      NONE   entity declarations
f       function     yes     no      0      NONE   function prototypes and declarations
l       local        no      no      0      NONE   local definitions
p       procedure    yes     no      0      NONE   procedure prototypes and declarations
r       record       yes     no      0      NONE   record names
t       type         yes     no      0      NONE   type definitions

We don't regard DESCRIPTION as the part of ctags CLI that we should keep the compatibility. The value for DESCRIPTION does not appear in tags output. What I would like to know is NAME. The NAME is part of the CLI. The value for NAME appears in tags output. So a tool reading a tags file may depend on the value of NAME. My original question is whether "port" is a proper kind NAME or not. I think "port" as NAME is o.k. What I have to update is the DESCRIPTION field for "port" kind:

diff --git a/parsers/vhdl.c b/parsers/vhdl.c
index 868c02e3..e276d978 100644
--- a/parsers/vhdl.c
+++ b/parsers/vhdl.c
@@ -204,7 +204,7 @@ static kindDefinition VhdlKinds[] = {
    {true, 'P', "package", "package definitions"},
    {false, 'l', "local", "local definitions"},
    {true, 'a', "architecture", "architectures"},
-   {false, 'q', "port", "ports"},
+   {false, 'q', "port", "port declarations"},
 };

With this change, --list-kinds-full=VHDL reports:

...
p       procedure    yes     no      0      NONE   procedure prototypes and declarations
q       port         no      no      0      NONE   port declarations
r       record       yes     no      0      NONE   record names
...
pidgeon777 commented 3 years ago

I think "port" as NAME is o.k.

I confirm.

q port no no 0 NONE port declarations

Also this would be perfect.

But, speaking of a port, it would be essential in my opinion to attach it to a scope. Or, if you prefer, given a port called PORT_C, this could be declared in two or more different entities, thus the name of the entity should be used as scope for the port.

Example:

entity ENTITY_A is
  generic (
    GENERIC_C : integer := value;
  );
  port (
    PORT_C : in std_logic
  );
end entity;

entity ENTITY_B is
  generic (
    GENERIC_C : integer := value;
  );
  port (
    PORT_C : in std_logic
  );
end entity;

Parsed tags:

 6:PORT_C   scope:entity:ENTITY_A
15:PORT_C   scope:entity:ENTITY_B

Also we could have:

component COMPONENT_A is
  generic (
    GENERIC_C : integer := value;
  );
  port (
    PORT_C : in std_logic
  );
end entity;

component COMPONENT_B is
  generic (
    GENERIC_C : integer := value;
  );
  port (
    PORT_C : in std_logic
  );
end entity;

Parsed tags:

 6:PORT_C   scope:component:COMPONENT_A
15:PORT_C   scope:component:COMPONENT_B
masatake commented 3 years ago

Thank you for the detailed description. In #2695, I already filled the scope fields of port declarations if they are in entities.

I did nothing for port declarations in components. I will revise my change.

masatake commented 3 years ago

With the change proposed in #2695, the VHDL parser can extract ports and generics declared in an entity and component.

$  u-ctags --list-kinds-full=VHDL 
#LETTER NAME         ENABLED REFONLY NROLES MASTER DESCRIPTION
C       component    no      no      0      NONE   component declarations
P       package      yes     no      0      NONE   package definitions
T       subtype      yes     no      0      NONE   subtype definitions
a       architecture yes     no      0      NONE   architectures
c       constant     yes     no      0      NONE   constant declarations
d       prototype    no      no      0      NONE   prototypes
e       entity       yes     no      0      NONE   entity declarations
f       function     yes     no      0      NONE   function prototypes and declarations
g       generic      no      no      0      NONE   generic declarations
l       local        no      no      0      NONE   local definitions
p       procedure    yes     no      0      NONE   procedure prototypes and declarations
q       port         no      no      0      NONE   port declarations
r       record       yes     no      0      NONE   record names
t       type         yes     no      0      NONE   type definitions
$  cat input.vhd                          
-- https://www.ics.uci.edu/~jmoorkan/vhdlref/Synario%20VHDL%20Manual.pdf
entity logical_ops_1 is
  port (a, b, c, d: in bit;
        m: out bit);
end logical_ops_1;
$  u-ctags --sort=no --kinds-VHDL='*' -o - input.vhd
logical_ops_1   input.vhd   /^entity logical_ops_1 is$/;"   e
a   input.vhd   /^  port (a, b, c, d: in bit;$/;"   q   entity:logical_ops_1
b   input.vhd   /^  port (a, b, c, d: in bit;$/;"   q   entity:logical_ops_1
c   input.vhd   /^  port (a, b, c, d: in bit;$/;"   q   entity:logical_ops_1
d   input.vhd   /^  port (a, b, c, d: in bit;$/;"   q   entity:logical_ops_1
m   input.vhd   /^        m: out bit);$/;"  q   entity:logical_ops_1
$  cat input-0.vhd                                  
-- Taken from https://github.com/universal-ctags/ctags/issues/2678
-- commented by @pidgeon777.
entity ENTITY_A is
  generic (
    GENERIC_C : integer := value;
  );
  port (
    PORT_C : in std_logic
  );
end entity;

entity ENTITY_B is
  generic (
    GENERIC_C : integer := value;
  );
  port (
    PORT_C : in std_logic
  );
end entity;
$  u-ctags --sort=no --kinds-VHDL='*' -o - input-0.vhd
ENTITY_A    input-0.vhd /^entity ENTITY_A is$/;"    e
GENERIC_C   input-0.vhd /^    GENERIC_C : integer := value;$/;" g   entity:ENTITY_A
PORT_C  input-0.vhd /^    PORT_C : in std_logic$/;" q   entity:ENTITY_A
ENTITY_B    input-0.vhd /^entity ENTITY_B is$/;"    e
GENERIC_C   input-0.vhd /^    GENERIC_C : integer := value;$/;" g   entity:ENTITY_B
PORT_C  input-0.vhd /^    PORT_C : in std_logic$/;" q   entity:ENTITY_B
$  cat input-1.vhd                                    
-- Taken from https://github.com/universal-ctags/ctags/issues/2678
-- commented by @pidgeon777.
component COMPONENT_A is
  generic (
    GENERIC_C : integer := value;
  );
  port (
    PORT_C : in std_logic
  );
end entity;

component COMPONENT_B is
  generic (
    GENERIC_C : integer := value;
  );
  port (
    PORT_C : in std_logic
  );
end entity;
$  u-ctags --sort=no --kinds-VHDL='*' -o - input-1.vhd
COMPONENT_A input-1.vhd /^component COMPONENT_A is$/;"  C
GENERIC_C   input-1.vhd /^    GENERIC_C : integer := value;$/;" g   component:COMPONENT_A
PORT_C  input-1.vhd /^    PORT_C : in std_logic$/;" q   component:COMPONENT_A
COMPONENT_B input-1.vhd /^component COMPONENT_B is$/;"  C
GENERIC_C   input-1.vhd /^    GENERIC_C : integer := value;$/;" g   component:COMPONENT_B
PORT_C  input-1.vhd /^    PORT_C : in std_logic$/;" q   component:COMPONENT_B

The last one is signal that I should work on before working on process and instance.

masatake commented 3 years ago

If I did something wrong, let me know.

masatake commented 3 years ago

@pidgeon777,

component COMPONENT_A is
  generic (
    GENERIC_C : integer := value;
  );
  port (
    PORT_C : in std_logic
  );
end entity;

Is the last line, "end entity;" correct? After reading some articles about VHDL, I guess the line should be "end component;" ?

pidgeon777 commented 3 years ago

Is the last line, "end entity;" correct?

My fault, when I copied-pasted the component declaration I forgot to change the last line. I will pay more attention the next time.

Correct component declaration is:

component COMPONENT_A is
  generic (
    GENERIC_C : integer := value
  );
  port (
    PORT_C : in std_logic
  );
end component [COMPONENT_A];

Note that the component name at the end of end component is not mandatory in code, only optional. Thus I included it into the square brackets.

More in general, for the component declaration:

component component_name [ is ] 
  [ generic ( generic_list ); ] 
  [ port ( port_list ); ] 
end component [ component_name ]; 

I highly suggest this reference for VHDL declarations and definitions:

https://www.hdlworks.com/hdl_corner/vhdl_ref/

With the change proposed in #2695, the VHDL parser can extract ports and generics declared in an entity and component.

Let's now consider the following situation. ENTITY_TOP instantiate both ENTITY_1 and ENTITY_2:

input.vhd:

library ieee;
use ieee.std_logic_1164.all;

entity ENTITY_TOP is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

architecture arch of ENTITY_TOP is
  signal sig : std_logic := '0';

  component ENTITY_1
    generic (
      GEN : integer := 0
    );
    port (
      INP : in std_logic
    );
  end component;

  component ENTITY_2
    generic (
      GEN : integer := 0
    );
    port (
      INP : in std_logic
    );
  end component;

begin

  ENTITY_1_i : ENTITY_1
  generic map(
    GEN => 0
  )
  port map(
    INP => '0'
  );

  ENTITY_2_i : ENTITY_2
  generic map(
    GEN => 0
  )
  port map(
    INP => '0'
  );

end architecture;

input-0.vhd:

library ieee;
use ieee.std_logic_1164.all;

entity ENTITY_1 is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

architecture arch of ENTITY_1 is

  signal sig : std_logic := '0';

begin
end architecture;

input-1.vhd:

library ieee;
use ieee.std_logic_1164.all;

entity ENTITY_2 is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

architecture arch of ENTITY_2 is

  signal sig : std_logic := '0';

begin
end architecture;

We can note the following:

1) GEN generic is the same name for all of the three entities, and also the two components, and finally the two component instantiations. Should the entity or component name be used as a scope to differentiate the various GEN tags? Example: GEN:scope:entity:ENTITY_TOP, GEN:scope:entity:ENTITY_1, GEN:scope:entity:ENTITY_2, GEN:scope:component:ENTITY_1, GEN:scope:component:ENTITY_2, GEN:scope:instance:ENTITY_1, GEN:scope:instance:ENTITY_2. 2) INP generic is the same name for all of the three entities, and also the two components, and finally the two component instantiations. Should the entity or component name be used as a scope to differentiate the various INP tags? Example: INP:scope:entity:ENTITY_TOP, INP:scope:entity:ENTITY_1, INP:scope:entity:ENTITY_2, INP:scope:component:ENTITY_1, INP:scope:component:ENTITY_2, INP:scope:instance:ENTITY_1, INP:scope:instance:ENTITY_2. 3) arch is the same name for the architecture of the three entities. Should the entity name be used as a scope to differentiate the three arch tags? Example: arch:scope:ENTITY_TOP, arch:scope:ENTITY_1, arch:scope:ENTITY_2. 4) sig is the same name for the signal of the three architectures. Should the entity and architecture name be used as a scope to differentiate the three arch tags? Example: sig:scope:arch:ENTITY_TOP, sig:scope:arch:ENTITY_1, sig:scope:arch:ENTITY_2. Both entity and architecture because an entity can have multiple architectures sharing the definition of a signal with the same name, and the same signal name could be used in the architecture of different entities.


@masatake added file names for each example code.

masatake commented 3 years ago
  1. yes.
  2. yes.
  3. no. I decided to use entity: field to represent the relationship between architecture and its entity.
  4. yes.

I would like you to read https://docs.ctags.io/en/latest/units.html. I added test cases based on your input to my pull request. I would like you to read args.ctags, input(-[0-9])?.vhd, and expected tags. They explain how my improvement works.

I will explain 3 later.

masatake commented 3 years ago

You don't need to see changes for files under Units/review-needed.r/test.vhd.t/. They are too large.

masatake commented 3 years ago

After rethinking about 3., I should use the scope field instead of the entity field for representing the relationship between architecture and entity. This breaks compatibilities.

masatake commented 3 years ago

process was added in #2695 .

instance_label: component_name
    generic map (generic_association_list)
    port map (port_association_list);

I think instance_label should be tagged with "instance" kind. typeref field can be used to attach "component_name" to the tag. component_name is tagged as a reference tag with "component" kind.

instance_label  input.vhd /^...$/;"  kind:instance scope:... typeref:component:component_name roles:def
component_nameinput.vhd /^...$/;"  kind:component roles:instantiated instance:instance_label

instance: is a VHDL specific field.

I think I have to write a man page for the VHDL parser.

pidgeon777 commented 3 years ago

I would like you to read https://docs.ctags.io/en/latest/units.html. I added test cases based on your input to my pull request. I would like you to read args.ctags, input(-[0-9])?.vhd, and expected tags. They explain how my improvement works.

Ok I will read that.

After rethinking about 3., I should use the scope field instead of the entity field for representing the relationship between architecture and entity. This breaks compatibilities.

The fact is that:

So, for example:

ENTITY_1.vhd:

library ieee;
use ieee.std_logic_1164.all;

entity ENTITY_1 is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

architecture arch1 of ENTITY_1 is

  signal sig : std_logic := '0';

begin
end architecture;

architecture arch2 of ENTITY_1 is

  signal sig : std_logic := '0';

begin
end architecture;

ENTITY_2.vhd:

library ieee;
use ieee.std_logic_1164.all;

entity ENTITY_2 is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

architecture arch1 of ENTITY_2 is

  signal sig : std_logic := '0';

begin
end architecture;

architecture arch2 of ENTITY_2 is

  signal sig : std_logic := '0';

begin
end architecture;

ENTITY_TOP.vhd:

library ieee;
use ieee.std_logic_1164.all;

entity ENTITY_TOP is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

architecture arch of ENTITY_TOP is
  signal sig : std_logic := '0';

  component ENTITY_1
    generic (
      GEN : integer := 0
    );
    port (
      INP : in std_logic
    );
  end component;

  component ENTITY_2
    generic (
      GEN : integer := 0
    );
    port (
      INP : in std_logic
    );
  end component;

begin

  ENTITY_1_i : entity work.ENTITY_1(arch1)
  generic map(
    GEN => 0
  )
  port map(
    INP => '0'
  );

  ENTITY_2_i : entity work.ENTITY_2(arch2)
  generic map(
    GEN => 0
  )
  port map(
    INP => '0'
  );

end architecture;

Some examples of expected tags:

ENTITY_TOP:entity

ENTITY_1:entity ENTITY_1:component:entity:ENTITY_TOP ENTITY_1:component instance:entity:ENTITY_TOP

ENTITY_2:entity ENTITY_2:component:entity:ENTITY_TOP ENTITY_2:component instance:entity:ENTITY_TOP

GEN:generic:entity:ENTITY_TOP GEN:generic:entity:ENTITY_1 GEN:generic:entity:ENTITY_2 GEN:generic:component:ENTITY_1:entity:ENTITY_TOP → Tag of the generic GEN of the component ENTITY_1 in ENTITY_TOP GEN:generic:component:ENTITY_2:entity:ENTITY_TOP → Tag of the generic GEN of the component ENTITY_2 in ENTITY_TOP GEN:generic:instance label:ENTITY_1_i:(component:ENTITY_1):entity:ENTITY_TOP ? Tag of the generic map GEN of the instance ENTITY_1_i of the component ENTITY_1 in ENTITY_TOP (instance label:ENTITY_1_i has to be associated to component:ENTITY_1, so the latter may be redundant for this particular tag of GEN, thus reported between parenthesis) GEN:generic:instance label:ENTITY_2_i:(component:ENTITY_2):entity:ENTITY_TOP ? Tag of the generic map GEN of the instance ENTITY_2_i of the component ENTITY_2 in ENTITY_TOP (instance label:ENTITY_2_i has to be associated to component:ENTITY_2, so the latter may be redundant for this particular tag of GEN, thus reported between parenthesis)

INP:port:entity:ENTITY_TOP INP:port:entity:ENTITY_1 INP:port:entity:ENTITY_2 INP:port:component:ENTITY_1:entity:ENTITY_TOP → Tag of the port INP of the component ENTITY_1 in ENTITY_TOP INP:port:component:ENTITY_2:entity:ENTITY_TOP → Tag of the port INP of the component ENTITY_2 in ENTITY_TOP INP:port:instance label:ENTITY_1_i:(component:ENTITY_1):entity:ENTITY_TOP → Tag of the port map INP of the instance ENTITY_1_i of the component ENTITY_1 in ENTITY_TOP (instance label:ENTITY_1_i has to be associated to component:ENTITY_1, so the latter may be redundant for this particular tag of INP, thus reported between parenthesis) INP:port:instance label:ENTITY_2_i:(component:ENTITY_2):entity:ENTITY_TOP → Tag of the port map INP of the instance ENTITY_2_i of the component ENTITY_2 in ENTITY_TOP (instance label:ENTITY_2_i has to be associated to component:ENTITY_2, so the latter may be redundant for this particular tag of INP, thus reported between parenthesis)

sig:signal:architecture:arch1:entity:ENTITY_TOP sig:signal:architecture:arch1:entity:ENTITY_1 sig:signal:architecture:arch2:entity:ENTITY_1 sig:signal:architecture:arch1:entity:ENTITY_2 sig:signal:architecture:arch2:entity:ENTITY_2

arch:architecture:entity:ENTITY_TOP

arch1:architecture:entity:ENTITY_1 arch1:architecture:entity:ENTITY_2 (arch1:architecture:instance label:ENTITY_1_i) ? Should enabled architecture of instanced component be tagged too? See ENTITY_1_i : entity work.ENTITY_1(arch1) (arch1:architecture:instance label:ENTITY_2_i) ? Should enabled architecture of instanced component be tagged too? See ENTITY_2_i : entity work.ENTITY_2(arch1)

arch2:architecture:entity:ENTITY_1 arch2:architecture:entity:ENTITY_2

ENTITY_1_i:instance label:component:ENTITY_1:entity:ENTITY_TOP → It is important to note that an instance label might not be associated to an instanced component (could be used for a generated statement instead, for example), so it could be a good idea to also use the component itself as a scope?

ENTITY_2_i:instance label:component:ENTITY_2:entity:ENTITY_TOP → It is important to note that an instance label might not be associated to an instanced component (could be used for a generated statement instead, for example), so it could be a good idea to also use the component itself as a scope?

The most vital things of all, which is really missing and would be extremely useful, is a way to recognize the tags of the components instantiated inside an entity. It should thus include the following:

component ENTITY_1
generic (
  GEN : integer := 0
);
port (
  INP : in std_logic
);
end component;

Basic tagging: component ENTITY_1. But we don't know if ENTITY_1 will be really instantiated or not, by only judging from this component statement.

And

ENTITY_1_i : entity work.ENTITY_1(arch1)
generic map(
  GEN => 0
)
port map(
  INP => '0'
);

Complete tagging: ENTITY_1_i : entity work.ENTITY_1(arch1). Now we know that ENTITY_1 will be instantiated.

Why this is vital information? Because it would make it possible to build a hierarchy of components. This would be of extreme help with:

masatake commented 3 years ago

Thank you. I found it will take more time to tag instantiations. So I would like to merge #2695 before working on instantiations.

Could you try #2695? With the change in the pull request, you can tag processes.

The following command line activates all the features I implemented in #2695.

$  ./ctags --options=NONE -o - --sort=no '--fields=+Kpre' '--extras=+r' '--kinds-VHDL=+{local}{prototype}{component}' --fields=+e INPUT.vhd
pidgeon777 commented 3 years ago

Hi, unfortunately, I am not a Github expert. I would like to deeply test your latest changes, but I don't know how I could do that. Is there an executable available somewhere for download? Or it is something which I should compile with the proper tools? In the latter case, would you suggest me the proper documentation to follow?

masatake commented 3 years ago

Which OS do you use?

pidgeon777 commented 3 years ago

Windows 10 x64 Pro and Windows 7 x64.

masatake commented 3 years ago

Before trying the VHDL branch, you must find a way to build ctags taken from the master branch. What you must know about git is very simple; type "git clone https://github.com/universal-ctags/ctags.git". Building it requires preparations and knowledge. In this area, I cannot help you because I don't use Windows. See https://docs.ctags.io/en/latest/windows.html. If you can build a ctags executable successfully, let me know it. I will explain the way to build the code at the branch for VHDL.

pidgeon777 commented 3 years ago

Unfortunately, I think I won't be able to run those tests soon, I got this critical issue:

https://github.com/universal-ctags/ctags/issues/2725

This happens when I try to run the Ctags versions released during the latest few months. Do you know if a way to solve this problem exists?

masatake commented 3 years ago

2725 is nothing to do with whether you can try the code proposed in #2695 or not.

2725 is about a pre-built binary.

There is no pre-built binary for #2695. To try #2695, you must build a ctags executable by yourself.

pidgeon777 commented 3 years ago

This is now clear, thank you. I'll try to build a ctags executable following your instructions, then.

pidgeon777 commented 3 years ago

Here I am again. I've successfully cloned the main ctags repository, also fetching your pull request, finally obtaining the new ctags executable with all of your new improvements.

I did some tests generating tags for the following input files:

ENTITY_1.vhd:

library ieee;
use ieee.std_logic_1164.all;

entity ENTITY_1 is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

architecture arch1 of ENTITY_1 is

  signal sig : std_logic := '0';

begin
  PROC_p: process(INP)
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------

  process
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------
end architecture;

architecture arch2 of ENTITY_1 is

  signal sig : std_logic := '0';

begin
  PROC_p: process(INP)
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------

  process
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------
end architecture;

ENTITY_2.vhd:


library ieee;
use ieee.std_logic_1164.all;

entity ENTITY_2 is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

architecture arch1 of ENTITY_2 is

  signal sig : std_logic := '0';

begin
  PROC_p: process(INP)
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------

  process
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------
end architecture;

architecture arch2 of ENTITY_2 is

  signal sig : std_logic := '0';

begin
  PROC_p: process(INP)
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------

  process
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------
end architecture;

ENTITY_TOP.vhd:

library ieee;
use ieee.std_logic_1164.all;

entity ENTITY_TOP is
  generic (
    GEN : integer := 0
  );
  port (
    INP : in std_logic
  );
end entity;

architecture arch of ENTITY_TOP is
  signal sig : std_logic := '0';

  component ENTITY_1
    generic (
      GEN : integer := 0
    );
    port (
      INP : in std_logic
    );
  end component;

  component ENTITY_2
    generic (
      GEN : integer := 0
    );
    port (
      INP : in std_logic
    );
  end component;

begin

  ENTITY_1_1 : entity work.ENTITY_1(arch1)
  generic map(
    GEN => GEN
  )
  port map(
    INP => INP
  );

  ENTITY_1_2 : entity work.ENTITY_1(arch2)
  generic map(
    GEN => GEN
  )
  port map(
    INP => INP
  );

  ENTITY_2_1 : entity work.ENTITY_2(arch1)
  generic map(
    GEN => GEN
  )
  port map(
    INP => INP
  );

  ENTITY_2_2 : entity work.ENTITY_2(arch2)
  generic map(
    GEN => GEN
  )
  port map(
    INP => INP
  );

  PROC_p: process(INP)
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------

  process
  -----------------------------
  variable var_v : integer := 0;
  -----------------------------
  begin
      -----------------------------
      var_v := 0;
      -----------------------------
      if (INP = '1') then
        sig <= '1';
      else
        sig <= '0';
      end if;
      -----------------------------
  end process;
  -----------------------------
end architecture;

Your recent changes improved a lot the VHDL parser, increasing its potential.

Now, here are some findings after having conducted some tests:

Regarding the missing tags, we have:

masatake commented 3 years ago

Now, here are some findings after having conducted some tests:

* `process` tag is missing a scope.  It should be:
  `architecture:entity_name.arch_name`

* `variable` tag scope is currently:
  `process:proc_name`
  It should be:
  `process:entity_name.arch_name.proc_name`

Thank you for trying.

I will update #2695 after trying to fix the above items. Then I will merge #2695. The pull requests contain so many commits. I will work on the rest of the items you put in the comments after merging #2695.

pidgeon777 commented 3 years ago

I was thinking of another critical thing. Let's consider this snippet again:

instance_label : entity library_name.entity_name(arch_name)
generic map(
  GEN => GEN
)
port map(
  PORT => PORT
);

As I observed in my previous post, a tag for instance_label (named e.g. instance label) should be added too, and I proposed this scope:

  1. architecture:top_entity.top_arch.entity_name.arch_name

Eventually, that scope could be reduced to the following:

  1. architecture:top_entity.top_arch

because instance label names are unique within an architecture. But option 1, albeit somewhat redundant, would give more information about the instance label tag, thus could be highly preferable during tag browsing.

But the critical missing thing, which I forgot about, would be a tag for the instanced component itself (entity_name in the above snippet). This tag could be called component instance (being its label, instance label) and its scope should then be:

instance label:top_entity.top_arch.instance_label

This would be vital for tags browsing. For example, starting from a given tag of an entity, it will then be possible to find:

A final observation, for the instance label generic/port tagging discussed in my previous post. As scope I suggested:

  1. instance label:top_entity.top_arch.entity_name.arch_name.instance_label

but this could be reduced to:

  1. instance label:top_entity.top_arch.instance_label

again because instance label names are unique within an architecture.

but variant 1 is the highly recommended one because it provides information about the entity and architecture couple related to the instance label.

masatake commented 3 years ago

@pidgeon777, do you think we can merge #2695? I think I solved the following items you pointed out:

pidgeon777 commented 3 years ago

@pidgeon777, do you think we can merge #2695?

I'm doing more tests for https://github.com/universal-ctags/ctags/pull/2695 before confirmation.

I think I solved the following items you pointed out

Are those included in the aforementioned https://github.com/universal-ctags/ctags/pull/2695?

masatake commented 3 years ago

Are those included in the aforementioned #2695?

Yes. https://github.com/universal-ctags/ctags/pull/2695/commits/cf9a5d2eebc884e992aeaa2edcc4627452d12c78 in #2695 is the change for the items.

pidgeon777 commented 3 years ago

Are those included in the aforementioned #2695?

Yes. cf9a5d2 in #2695 is the change for the items.

The new additions in https://github.com/universal-ctags/ctags/pull/2695 seem to be OK.

masatake commented 3 years ago

I merged #2695. Thank you for testing.

@pidgeon777, can I ask you to summarize the rest items? (opening a new issue is an alternative way.)

I have one request. When showing an example of scope field, could you add scope: prefix? ctags can emit the prefix when you give --fields=+Z option.

$ cat f.h
struct point {
    int x, y;
};
$ ./ctags -o - --fields=+Z f.h
point   f.h /^struct point {$/;"    s
x   f.h /^  int x, y;$/;"   m   scope:struct:point  typeref:typename:int
y   f.h /^  int x, y;$/;"   m   scope:struct:point  typeref:typename:int

I would like you to show the examples in the above forms.