Skip to content

Commit

Permalink
Add support for struct references
Browse files Browse the repository at this point in the history
Other changes:
* Add "parameters" parameter to Function constructor
  • Loading branch information
cogu committed Oct 15, 2023
1 parent 5cf8532 commit 26a32bd
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 25 deletions.
11 changes: 8 additions & 3 deletions examples/typedef_header.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@
code.append(C.blank())
code.append(C.sysinclude("stdint.h"))
code.append(C.blank())
struct = C.struct("heap_tag", members=[C.struct_member("pItem", "void", pointer=True),
C.struct_member("u32Value", "uint32_t")])
code.append(C.statement(C.typedef("heap_t", struct)))
code.append([C.statement(C.struct_ref("os_task_tag")), C.line_comment("Forward declaration")])
code.append(C.blank())
struct = C.struct("os_alarm_cfg_tag",
members=[C.struct_member("taskPtr", C.struct_ref("os_task_tag", pointer=True)),
C.struct_member("eventMask", "uint32_t"),
C.struct_member("initDelayMs", "uint32_t"),
C.struct_member("periodMs", "uint32_t")])
code.append(C.statement(C.typedef("os_alarm_cfg_t", struct)))
code.append(C.blank())
code.append(C.ifndef("__cplusplus"))
code.append(C.line("}"))
Expand Down
33 changes: 23 additions & 10 deletions src/cfile/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,13 +222,19 @@ def make_member(self,
return member


class StructRef(Type):
"""
Reference to struct type
"""


class Variable(Element):
"""
Variable declaration
"""
def __init__(self,
name: str,
data_type: str | Type | Struct,
data_type: str | Type | Struct | StructRef,
const: bool = False, # Only used as pointer qualifier
pointer: bool = False,
extern: bool = False,
Expand Down Expand Up @@ -270,15 +276,15 @@ class TypeDef(Element):
"""
def __init__(self,
name: str,
data_type: str | Type | Struct,
data_type: str | Type | Struct | StructRef,
const: bool = False, # Only used as pointer qualifier
pointer: bool = False,
array: int | None = None) -> None:
self.name = name
self.const = const
self.pointer = pointer
self.array = array
if isinstance(data_type, (Type, Struct)):
if isinstance(data_type, (StructRef, Struct, Type)):
self.data_type = data_type
elif isinstance(data_type, str):
self.data_type = Type(data_type)
Expand All @@ -303,11 +309,12 @@ def __init__(self,
name: str,
return_type: str | Type | None = None,
static: bool = False,
const: bool = False, # This is not const of the return type
extern: bool = False) -> None:
const: bool = False, # const function (as seen in C++)
extern: bool = False,
parameters: Variable | list[Variable] | None = None) -> None:
self.name = name
self.static = static
self.const = const # Const function (as seen in C++)
self.const = const
self.extern = extern
if isinstance(return_type, Type):
self.return_type = return_type
Expand All @@ -318,10 +325,16 @@ def __init__(self,
else:
raise TypeError(str(type(return_type)))
self.params: list[Variable] = []

def add_param(self, param: Variable) -> "Function":
if parameters is not None:
if isinstance(parameters, Variable):
self.append(parameters)
elif isinstance(parameters, list):
for parameter in parameters:
self.append(parameter)

def append(self, param: Variable) -> "Function":
"""
Add function parameter
Adds new function parameter
"""
if not isinstance(param, (Variable)):
raise TypeError("Expected Variable or FunctionPtr object")
Expand All @@ -338,7 +351,7 @@ def make_param(self,
Creates new Variable from arguments and adds as parameter
"""
param = Variable(name, data_type, const=const, pointer=pointer, array=array)
return self.add_param(param)
return self.append(param)


class FunctionCall(Element):
Expand Down
11 changes: 11 additions & 0 deletions src/cfile/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,17 @@ def struct(self,
"""
return core.Struct(name, members)

def struct_ref(self,
name: str,
const: bool = False,
pointer: bool = False,
volatile: bool = False,
array: int | None = None) -> core.StructRef:
"""
New struct reference
"""
return core.StructRef(name, const, pointer, volatile, array)

def variable(self,
name: str,
data_type: str | core.Type | core.Struct,
Expand Down
12 changes: 8 additions & 4 deletions src/cfile/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ def __init__(self, style: c_style.StyleOptions) -> None:
"EndifDirective": self._write_endif_directive,
"Extern": self._write_extern,
"Struct": self._write_struct,
"StructRef": self._write_type,
}
self.last_element = ElementType.NONE

Expand Down Expand Up @@ -262,7 +263,7 @@ def _format_block_comment(self, lines: list[str], wrap_text: bool, width: int, l
self._write_line(line_start + line)
self._write(lines[-1] + f"{'*'*width}/")

def _write_type(self, elem: core.Type) -> None:
def _write_type(self, elem: core.Type | core.StructRef) -> None:
"""
Writes data type
"""
Expand All @@ -287,14 +288,17 @@ def _format_type(self, elem: core.Type) -> str:
raise RuntimeError(f"Used qualifier '{key}' not part of selected qualifier_order list")
return " ".join(parts)

def _format_type_part(self, elem: core.Type) -> str:
def _format_type_part(self, elem: core.Type | core.StructRef) -> str:
"""
Writes type name and pointer
"""
result = ""
if isinstance(elem, core.StructRef):
result += "struct "
if isinstance(elem.base_type, str):
result = elem.base_type
result += elem.base_type
else:
result = self._format_type(elem.base_type)
result += self._format_type(elem.base_type)
if elem.pointer:
if self.style.pointer_alignment == c_style.Alignment.LEFT:
result += "*"
Expand Down
62 changes: 54 additions & 8 deletions tests/test_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ def test_void_int_arg_using_make(self):
self.assertEqual(output, "void my_func(int arg1)")

def test_void_int_arg_manual(self):
element = core.Function("my_func", "void").add_param(core.Variable("arg1", "int"))
element = core.Function("my_func", "void").append(core.Variable("arg1", "int"))
writer = cfile.Writer(cfile.StyleOptions())
output = writer.write_str_elem(element)
self.assertEqual(output, "void my_func(int arg1)")
Expand Down Expand Up @@ -622,25 +622,24 @@ class TestStructDeclaration(unittest.TestCase):
def test_zero_sized_struct(self):
element = core.Struct("MyStruct")
writer = cfile.Writer(cfile.StyleOptions())
output = writer.write_str_elem(element)
expected = """struct MyStruct
{
}"""
self.assertEqual(expected, output)
self.assertEqual(expected, writer.write_str_elem(element))

def test_struct_with_int_member(self):
element = core.Struct("MyStruct", members=core.StructMember("first", "int"))
writer = cfile.Writer(cfile.StyleOptions())
output = writer.write_str_elem(element)
expected = """struct MyStruct
{
int first;
}"""
self.assertEqual(expected, output)
self.assertEqual(expected, writer.write_str_elem(element))

def test_typedef_struct_statement(self):
struct = core.Struct("Struct_IntPair", members=[core.StructMember("first", "int"),
core.StructMember("second", "int")])
struct = core.Struct("Struct_IntPair",
members=[core.StructMember("first", "int"),
core.StructMember("second", "int")])
statement = core.Statement(core.TypeDef("IntPair_T", struct))
writer = cfile.Writer(cfile.StyleOptions())
output = writer.write_str_elem(statement)
Expand All @@ -649,9 +648,56 @@ def test_typedef_struct_statement(self):
int first;
int second;
} IntPair_T;"""

self.assertEqual(expected, output)

def test_struct_declaration_with_struct_ref_member(self):
struct = core.Struct("os_alarm_cfg_tag",
members=[core.StructMember("taskPtr", core.StructRef("os_task_tag", pointer=True)),
core.StructMember("eventMask", "uint32_t"),
core.StructMember("initDelayMs", "uint32_t"),
core.StructMember("periodMs", "uint32_t")])
statement = core.Statement(core.TypeDef("os_alarm_cfg_t", struct))
writer = cfile.Writer(cfile.StyleOptions())
expected = """typedef struct os_alarm_cfg_tag
{
struct os_task_tag* taskPtr;
uint32_t eventMask;
uint32_t initDelayMs;
uint32_t periodMs;
} os_alarm_cfg_t;"""
self.assertEqual(expected, writer.write_str_elem(statement))


class TestStructRef(unittest.TestCase):

def test_struct_variable(self):
element = core.Variable("time", core.StructRef("timespec"))
writer = cfile.Writer(cfile.StyleOptions())
self.assertEqual('struct timespec time', writer.write_str_elem(element))

def test_struct_parameter(self):
element = core.Function("process_time", "void", parameters=[core.Variable("time", core.StructRef("timespec"))])
writer = cfile.Writer(cfile.StyleOptions())
self.assertEqual('void process_time(struct timespec time)', writer.write_str_elem(element))

def test_struct_return_and_struct_parameter(self):
element = core.Function("timespec_add",
core.StructRef("timespec"),
static=True,
parameters=[core.Variable("time1", core.StructRef("timespec")),
core.Variable("time2", core.StructRef("timespec"))])
writer = cfile.Writer(cfile.StyleOptions())
output = writer.write_str_elem(element)
self.assertEqual('static struct timespec timespec_add(struct timespec time1, struct timespec time2)', output)

def test_struct_forward_declaration(self):
"""
Forward declaration of struct as a separate statement
"""
element = core.Statement(core.StructRef("os_task_tag"))
writer = cfile.Writer(cfile.StyleOptions())
self.assertEqual('struct os_task_tag;', writer.write_str_elem(element))


if __name__ == '__main__':
unittest.main()

0 comments on commit 26a32bd

Please sign in to comment.