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 support to variable with [] inside type #85

Merged
merged 5 commits into from
May 22, 2024
Merged
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
88 changes: 61 additions & 27 deletions CppHeaderParser/CppHeaderParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ def trace_print(*args):
_BRACE_REASON_OTHER = 0
_BRACE_REASON_NS = 1
_BRACE_REASON_EXTERN = 2
_BRACE_REASON_VARIABLE = 3

# Track what was added in what order and at what depth
parseHistory = []
Expand Down Expand Up @@ -239,10 +240,13 @@ def is_property_namestack(nameStack):
r = False
if "(" not in nameStack and ")" not in nameStack:
r = True
elif (
"(" in nameStack
and "=" in nameStack
and nameStack.index("=") < nameStack.index("(")
elif "(" in nameStack and (
( # = initialization
"=" in nameStack and nameStack.index("=") < nameStack.index("(")
)
or ( # {} initialization
"{" in nameStack and nameStack.index("{") < nameStack.index("(")
)
):
r = True
# See if we are a function pointer
Expand Down Expand Up @@ -1217,29 +1221,48 @@ def __init__(self, nameStack, doxygen, location, is_var=True, **kwargs):
else:
self["extern"] = False

if "=" in nameStack:
self["type"] = " ".join(nameStack[: nameStack.index("=") - 1])
self["name"] = nameStack[nameStack.index("=") - 1]
default = " ".join(nameStack[nameStack.index("=") + 1 :])
nameStack = nameStack[: nameStack.index("=")]
default = self._filter_name(default)
self["default"] = default
# backwards compat; deprecate camelCase in dicts
self["defaultValue"] = default
elif "{" in nameStack and "}" in nameStack:
posBracket = nameStack.index("{")
self["type"] = " ".join(nameStack[: posBracket - 1])
self["name"] = nameStack[posBracket - 1]
default = " ".join(nameStack[posBracket + 1 : -1])
nameStack = nameStack[:posBracket]
default = self._filter_name(default)
self["default"] = default
# backwards compat; deprecate camelCase in dicts
self["defaultValue"] = default

_stack_ = nameStack
if "[" in nameStack: # strip off array informatin
arrayStack = nameStack[nameStack.index("[") :]
if nameStack.count("[") > 1:
self["array"] = 0
while "]" in nameStack[-1]: # strip off array information
arrayPos = len(nameStack) - 1 - nameStack[::-1].index("[")
arrayStack = nameStack[arrayPos:]
if self["array"] == 1:
debug_print("Multi dimensional array")
debug_print("arrayStack=%s", arrayStack)
nums = [x for x in arrayStack if x.isdigit()]
# Calculate size by multiplying all dimensions
p = 1
for n in nums:
p *= int(n)
if len(arrayStack) == 3:
n = arrayStack[1]
# Multi dimensional array
self["array_size"] = p
if not "multi_dimensional_array_size" in self:
self["multi_dimensional_array_size"] = self["array_size"]
self["multi_dimensional_array_size"] += "x" + n
self["array_size"] = str(int(self["array_size"]) * int(n))
self["multi_dimensional_array"] = 1
self["multi_dimensional_array_size"] = "x".join(nums)
else:
debug_print("Array")
if len(arrayStack) == 3:
self["array_size"] = arrayStack[1]
nameStack = nameStack[: nameStack.index("[")]
nameStack = nameStack[:arrayPos]
self["array"] = 1
else:
self["array"] = 0
nameStack = self._name_stack_helper(nameStack)

if doxygen:
Expand Down Expand Up @@ -1268,15 +1291,6 @@ def __init__(self, nameStack, doxygen, location, is_var=True, **kwargs):
)
self["function_pointer"] = 1

elif "=" in nameStack:
self["type"] = " ".join(nameStack[: nameStack.index("=") - 1])
self["name"] = nameStack[nameStack.index("=") - 1]
default = " ".join(nameStack[nameStack.index("=") + 1 :])
default = self._filter_name(default)
self["default"] = default
# backwards compat; deprecate camelCase in dicts
self["defaultValue"] = default

elif (
is_fundamental(nameStack[-1])
or nameStack[-1] in [">", "<", ":", "."]
Expand Down Expand Up @@ -2931,7 +2945,23 @@ def __init__(
continue

if parenDepth == 0 and tok.type == "{":
self.lastBraceReason = _BRACE_REASON_OTHER
if self.nameStack[0] in (
"class",
"struct",
"union",
"namespace",
"enum",
"extern",
"typedef",
) or (is_method_namestack(self.stack) or (not self.curClass)):
self.lastBraceReason = _BRACE_REASON_OTHER
else:
# Case : type variable {init};
self.lastBraceReason = _BRACE_REASON_VARIABLE
self.braceDepth += 1
self.braceReason.append(self.lastBraceReason)
self.nameStack.append(tok.value)
continue
if len(self.nameStack) >= 2 and is_namespace(
self.nameStack
): # namespace {} with no name used in boost, this sets default?
Expand Down Expand Up @@ -2991,6 +3021,10 @@ def __init__(
self.linkage_stack.pop()
self.stack = [] # clear stack when linkage ends?
self.stmtTokens = []
# Case : type variable {init};
elif reason == _BRACE_REASON_VARIABLE:
self.nameStack.append(tok.value)
continue
else:
self._evaluate_stack()
self.braceDepth -= 1
Expand Down
85 changes: 84 additions & 1 deletion test/test_CppHeaderParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2364,7 +2364,7 @@ def setUp(self):
def test_array_size(self):
self.assertEqual(
self.cppHeader.classes["Picture"]["properties"]["public"][1]["array_size"],
16384,
"16384",
)

def test_multi_dimensional_array_size(self):
Expand Down Expand Up @@ -4227,5 +4227,88 @@ def test_fn(self):
self.assertEqual(fn["linkage"], "")


# Github PR 85
class ContainerOfArray_TestCase(unittest.TestCase):
def setUp(self):
self.cppHeader = CppHeaderParser.CppHeader(
"""
class ContainerOfArray {
public:
std::unique_ptr<int[]> variable;
std::unique_ptr<int[]> function(std::unique_ptr<int[]> param1);
};
""",
"string",
)

def test_rtntype(self):
self.assertEqual(
self.cppHeader.classes["ContainerOfArray"]["methods"]["public"][0][
"rtnType"
],
"std::unique_ptr<int [ ] >",
)

def test_parameters(self):
self.assertEqual(
filter_pameters(
self.cppHeader.classes["ContainerOfArray"]["methods"]["public"][0][
"parameters"
]
),
[{"name": "param1", "desc": None, "type": "std::unique_ptr<int [ ] >"}],
)

def test_member(self):
self.assertEqual(
self.cppHeader.classes["ContainerOfArray"]["properties"]["public"][0][
"name"
],
"variable",
)
self.assertEqual(
self.cppHeader.classes["ContainerOfArray"]["properties"]["public"][0][
"type"
],
"std::unique_ptr<int [ ] >",
)


class InitBracket_TestCase(unittest.TestCase):
def setUp(self):
self.cppHeader = CppHeaderParser.CppHeader(
"""
class InitBracket {
public:
int variable{10};
std::shared_ptr<int> variable2 {std::make_shared<int>(150)};
};
""",
"string",
)

def test_member(self):
self.assertEqual(
self.cppHeader.classes["InitBracket"]["properties"]["public"][0]["name"],
"variable",
)
self.assertEqual(
self.cppHeader.classes["InitBracket"]["properties"]["public"][0][
"defaultValue"
],
"10",
)
self.assertEqual(
self.cppHeader.classes["InitBracket"]["properties"]["public"][1]["name"],
"variable2",
)
self.assertEqual(
self.cppHeader.classes["InitBracket"]["properties"]["public"][1][
"defaultValue"
],
"std::make_shared<int> ( 150 )",
)


if __name__ == "__main__":
unittest.main()
Loading