Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rudimentary support for C++20 concepts #160

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion exhale/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,9 @@ def __init__(self, name, kind, refid):
self.parameters = [] # list of strings: ["int", "int"] for foo(int x, int y)
self.template = None # list of strings

if self.kind == "concept":
self.template = None # list of strings

def __lt__(self, other):
'''
The ``ExhaleRoot`` class stores a bunch of lists of ``ExhaleNode`` objects.
Expand Down Expand Up @@ -296,8 +299,13 @@ def full_signature(self):
name=self.name,
parameters=", ".join(self.parameters)
)
if self.kind == "concept":
return "{template} {name}".format(
template="template <{0}> ".format(", ".join(self.template)) if self.template is not None else "",
name=self.name)

raise RuntimeError(
"full_signature may only be called for a 'function', but {name} is a '{kind}' node.".format(
"full_signature may only be called for a 'function' or 'concept', but {name} is a '{kind}' node.".format(
name=self.name, kind=self.kind
)
)
Expand Down Expand Up @@ -995,6 +1003,9 @@ class ExhaleRoot(object):
ExhaleNode it came from. Storing it this way is convenient for when the
Doxygen xml file is being parsed.

``concepts`` (list)
The full list of ExhaleNodes of kind ``concept``

``class_like`` (list)
The full list of ExhaleNodes of kind ``struct`` or ``class``

Expand Down Expand Up @@ -1071,6 +1082,8 @@ def __init__(self):
# doxygenindex <-+-> IGNORE |
# autodoxygenindex <-+-> IGNORE |
# -------------------+----------------+
# doxygenconcept <-+-> "concept" |
self.concepts = [] # |
# doxygenclass <-+-> "class" |
# doxygenstruct <-+-> "struct" |
self.class_like = [] # |
Expand Down Expand Up @@ -1655,6 +1668,8 @@ def trackNodeIfUnseen(self, node):
node.set_owner(self)
self.all_nodes.append(node)
self.node_by_refid[node.refid] = node
if node.kind == "concept":
self.concepts.append(node)
if node.kind == "class" or node.kind == "struct":
self.class_like.append(node)
elif node.kind == "namespace":
Expand Down Expand Up @@ -2200,6 +2215,7 @@ def sortInternals(self):
# have each node sort its children
# leaf-like lists: no child sort
self.defines.sort()
self.concepts.sort()
self.enums.sort()
self.enum_values.sort()
self.functions.sort()
Expand Down Expand Up @@ -3009,6 +3025,7 @@ def generateNamespaceChildrenString(self, nspace):
# sort the children
nsp_namespaces = []
nsp_nested_class_like = []
nsp_concepts = []
nsp_enums = []
nsp_functions = []
nsp_typedefs = []
Expand All @@ -3029,6 +3046,8 @@ def generateNamespaceChildrenString(self, nspace):
child.findNestedClassLike(nsp_nested_class_like)
child.findNestedEnums(nsp_enums)
child.findNestedUnions(nsp_unions)
elif child.kind == "concept":
nsp_concepts.append(child)
elif child.kind == "enum":
nsp_enums.append(child)
elif child.kind == "function":
Expand All @@ -3043,6 +3062,7 @@ def generateNamespaceChildrenString(self, nspace):
# generate their headings if they exist (no Defines...that's not a C++ thing...)
children_stream = StringIO()
self.generateSortedChildListString(children_stream, "Namespaces", nsp_namespaces)
self.generateSortedChildListString(children_stream, "Concepts", nsp_concepts)
self.generateSortedChildListString(children_stream, "Classes", nsp_nested_class_like)
self.generateSortedChildListString(children_stream, "Enums", nsp_enums)
self.generateSortedChildListString(children_stream, "Functions", nsp_functions)
Expand Down Expand Up @@ -3255,6 +3275,7 @@ def generateFileNodeDocuments(self):

# generate their headings if they exist --- DO NOT USE findNested*, these are included recursively
file_structs = []
file_concepts = []
file_classes = []
file_enums = []
file_functions = []
Expand All @@ -3265,6 +3286,8 @@ def generateFileNodeDocuments(self):
for child in f.children:
if child.kind == "struct":
file_structs.append(child)
elif child.kind == "concept":
file_concepts.append(child)
elif child.kind == "class":
file_classes.append(child)
elif child.kind == "enum":
Expand All @@ -3283,6 +3306,7 @@ def generateFileNodeDocuments(self):
# generate the listing of children referenced to from this file
children_stream = StringIO()
self.generateSortedChildListString(children_stream, "Namespaces", f.namespaces_used)
self.generateSortedChildListString(children_stream, "Concepts", file_concepts)
self.generateSortedChildListString(children_stream, "Classes", file_structs + file_classes)
self.generateSortedChildListString(children_stream, "Enums", file_enums)
self.generateSortedChildListString(children_stream, "Functions", file_functions)
Expand Down Expand Up @@ -3936,6 +3960,7 @@ class view hierarchy. It will be present in the file page it was declared in
Currently, the API is generated in the following (somewhat arbitrary) order:

- Namespaces
- Concepts
- Classes and Structs
- Enums
- Unions
Expand Down Expand Up @@ -4013,6 +4038,7 @@ def __len__(self):

dump_order = [
("Namespaces", "namespace"),
("Concepts", "concept"),
("Classes and Structs", "class"), # NOTE: class/struct stored together!
("Enums", "enum"),
("Unions", "union"),
Expand Down Expand Up @@ -4105,6 +4131,7 @@ def toConsole(self):
console. Unused in the release, but is helpful for debugging ;)
'''
fmt_spec = {
"concept": utils.AnsiColors.BOLD_MAGENTA,
"class": utils.AnsiColors.BOLD_MAGENTA,
"struct": utils.AnsiColors.BOLD_CYAN,
"define": utils.AnsiColors.BOLD_YELLOW,
Expand All @@ -4123,6 +4150,7 @@ def toConsole(self):

self.consoleFormat(
"{0} and {1}".format(
utils._use_color("Concepts", fmt_spec["concept"], sys.stderr),
utils._use_color("Classes", fmt_spec["class"], sys.stderr),
utils._use_color("Structs", fmt_spec["struct"], sys.stderr),
),
Expand Down
6 changes: 6 additions & 0 deletions exhale/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ def get_time():


AVAILABLE_KINDS = [
"concept",
"class",
"define",
"dir",
Expand All @@ -127,6 +128,7 @@ def get_time():
"define",
"enum",
"function",
"concept",
"class",
"struct",
"typedef",
Expand Down Expand Up @@ -401,6 +403,8 @@ def qualifyKind(kind):
+=============+==================+
| "class" | "Class" |
+-------------+------------------+
| "concept" | "Concept" |
+-------------+------------------+
| "define" | "Define" |
+-------------+------------------+
| "enum" | "Enum" |
Expand Down Expand Up @@ -456,6 +460,8 @@ def kindAsBreatheDirective(kind):
+-------------+--------------------+
| Input Kind | Output Directive |
+=============+====================+
| "concept" | "doxygenconcept" |
+-------------+--------------------+
| "class" | "doxygenclass" |
+-------------+--------------------+
| "define" | "doxygendefine" |
Expand Down