diff options
Diffstat (limited to 'python/vhdl_langserver/references.py')
-rw-r--r-- | python/vhdl_langserver/references.py | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/python/vhdl_langserver/references.py b/python/vhdl_langserver/references.py new file mode 100644 index 000000000..fa1033c04 --- /dev/null +++ b/python/vhdl_langserver/references.py @@ -0,0 +1,92 @@ +import logging +import libghdl.thin.vhdl.nodes as nodes +import libghdl.thin.vhdl.nodes_meta as nodes_meta +import libghdl.thin.vhdl.pyutils as pyutils +import libghdl.thin.name_table as name_table + +log = logging.getLogger(__name__) + +def find_def_chain(first, loc): + n1 = first + while n1 != nodes.Null_Iir: + res = find_def(n1, loc) + if res is not None: + return res + n1 = nodes.Get_Chain(n1) + return None + + +def find_def(n, loc): + "Return the node at location :param loc:, or None if not under :param n:" + if n == nodes.Null_Iir: + return None + k = nodes.Get_Kind(n) + if k in [nodes.Iir_Kind.Simple_Name, + nodes.Iir_Kind.Character_Literal, + nodes.Iir_Kind.Operator_Symbol, + nodes.Iir_Kind.Selected_Name, + nodes.Iir_Kind.Attribute_Name, + nodes.Iir_Kind.Selected_Element]: + n_loc = nodes.Get_Location(n) + if loc >= n_loc: + ident = nodes.Get_Identifier(n) + id_len = name_table.Get_Name_Length(ident) + if loc < n_loc + id_len: + return n + if k == nodes.Iir_Kind.Simple_Name: + return None + elif k == nodes.Iir_Kind.Design_File: + return find_def_chain(nodes.Get_First_Design_Unit(n), loc) + elif k == nodes.Iir_Kind.Design_Unit: + #if loc > elocations.Get_End_Location(unit): + # return None + res = find_def_chain(nodes.Get_Context_Items(n), loc) + if res is not None: + return res + unit = nodes.Get_Library_Unit(n) + return find_def(unit, loc) + + # This is *much* faster than using node_iter! + for f in pyutils.fields_iter(n): + typ = nodes_meta.get_field_type(f) + if typ == nodes_meta.types.Iir: + attr = nodes_meta.get_field_attribute(f) + if attr == nodes_meta.Attr.ANone: + res = find_def(nodes_meta.Get_Iir(n, f), loc) + if res is not None: + return res + elif attr == nodes_meta.Attr.Chain: + res = find_def_chain(nodes_meta.Get_Iir(n, f), loc) + if res is not None: + return res + elif attr == nodes_meta.Attr.Maybe_Ref: + if not nodes.Get_Is_Ref(n, f): + res = find_def(nodes_meta.Get_Iir(n, f), loc) + if res is not None: + return res + elif typ == nodes_meta.types.Iir_List: + attr = nodes_meta.get_field_attribute(f) + if attr == nodes_meta.Attr.ANone: + for n1 in pyutils.list_iter(nodes_meta.Get_Iir_List(n, f)): + res = find_def(n1, loc) + if res is not None: + return res + elif typ == nodes_meta.types.Iir_Flist: + attr = nodes_meta.get_field_attribute(f) + if attr == nodes_meta.Attr.ANone: + for n1 in pyutils.flist_iter(nodes_meta.Get_Iir_Flist(n, f)): + res = find_def(n1, loc) + if res is not None: + return res + + return None + +def goto_definition(n, loc): + "Return the declaration (as a node) under :param loc: or None" + ref = find_def(n, loc) + log.debug("for loc %u found node %s", loc, ref) + if ref is None: + return None + log.debug("for loc %u id=%s", loc, name_table.Get_Name_Ptr(nodes.Get_Identifier(ref)).decode('utf-8')) + ent = nodes.Get_Named_Entity(ref) + return None if ent == nodes.Null_Iir else ent |