Skip to content

Commit

Permalink
Add union support
Browse files Browse the repository at this point in the history
Signed-off-by: Cervenka Dusan <[email protected]>
  • Loading branch information
Hadatko committed Nov 13, 2024
1 parent 7ed5d25 commit 06506ef
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 46 deletions.
104 changes: 66 additions & 38 deletions src/cfile/core.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
cfile core
"""
from typing import Union, Any
from typing import Any, Self


class Element:
Expand Down Expand Up @@ -145,7 +145,7 @@ class Type(DataType):
Data type
"""
def __init__(self,
base_type: Union[str, "Type"],
base_type: str | Self,
const: bool = False,
pointer: bool = False,
volatile: bool = False,
Expand Down Expand Up @@ -231,46 +231,32 @@ def make_member(self,
return member


class TypeDef(DataType):
"""
Type definition (typedef)
"""
def __init__(self,
name: str,
base_type: Union[str, "DataType", "Declaration"],
const: bool = False,
pointer: bool = False,
volatile: bool = False,
array: int | None = None) -> None:
super().__init__(name)
self.const = const
self.volatile = volatile
class UnionMember(Element):
def __init__(self, name: str, data_type: DataType, pointer: bool = False, array: int | None = None):
self.name = name
self.data_type = data_type
self.pointer = pointer
self.array = array
self.base_type: DataType | Declaration
if isinstance(base_type, DataType):
self.base_type = base_type
elif isinstance(base_type, str):
self.base_type = Type(base_type)
elif isinstance(base_type, Declaration):
if not isinstance(base_type.element, DataType):
err_msg = f'base_type: Declaration must declare a type, not {str(type(base_type.element))}'
self.base_type = base_type


class Union(DataType):
def __init__(self, name: str, members: list[UnionMember] | None = None):
self.name = name

if members == None:
self.members = []
elif isinstance(members, list):
self.members: list[UnionMember] = list(members)
else:
err_msg = 'base_type: Invalid type, expected "str" | "DataType" | "Declaration",'
err_msg += ' got {str(type(base_type))}'
raise TypeError(err_msg)
raise TypeError('Invalid argument type for "members"')

def qualifier(self, name) -> bool:
def append(self, member: UnionMember) -> None:
"""
Returns the status of named qualifier
Appends new element to the struct definition
"""
if name == "const":
return self.const
if name == "volatile":
return self.volatile
else:
raise KeyError(name)
if not isinstance(member, UnionMember):
raise TypeError(f'Invalid type, expected "UnionMember", got {str(type(member))}')
self.members.append(member)


class Variable(Element):
Expand Down Expand Up @@ -374,7 +360,7 @@ class Declaration(Element):
- Function
"""
def __init__(self,
element: Union[Variable, Function, DataType],
element: Variable | Function | DataType,
init_value: Any | None = None) -> None:
if isinstance(element, (Variable, Function, DataType)):
self.element = element
Expand Down Expand Up @@ -484,7 +470,7 @@ class Sequence:
A sequence of statements, comments or whitespace
"""
def __init__(self) -> None:
self.elements: list[Union[Comment, Statement, "Sequence"]] = []
self.elements: list[Comment | Statement | Self] = []

def __len__(self) -> int:
return len(self.elements)
Expand All @@ -511,3 +497,45 @@ class Block(Sequence):
"""
A sequence wrapped in braces
"""

class TypeDef(DataType):
"""
Type definition (typedef)
"""

def __init__(self,
name: str,
base_type: str | DataType | Declaration,
const: bool = False,
pointer: bool = False,
volatile: bool = False,
array: int | None = None) -> None:
super().__init__(name)
self.const = const
self.volatile = volatile
self.pointer = pointer
self.array = array
self.base_type: DataType | Declaration
if isinstance(base_type, DataType):
self.base_type = base_type
elif isinstance(base_type, str):
self.base_type = Type(base_type)
elif isinstance(base_type, Declaration):
if not isinstance(base_type.element, DataType):
err_msg = f'base_type: Declaration must declare a type, not {str(type(base_type.element))}'
self.base_type = base_type
else:
err_msg = 'base_type: Invalid type, expected "str" | "DataType" | "Declaration",'
err_msg += ' got {str(type(base_type))}'
raise TypeError(err_msg)

def qualifier(self, name) -> bool:
"""
Returns the status of named qualifier
"""
if name == "const":
return self.const
if name == "volatile":
return self.volatile
else:
raise KeyError(name)
8 changes: 8 additions & 0 deletions src/cfile/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,11 @@ def declaration(self,

"""New declaration"""
return core.Declaration(element, init_value)

def union_member(self, name: str, dataType: core.DataType, pointer: bool = False, array: int | None = None) -> core.UnionMember:

return core.UnionMember(name, dataType, pointer, array)

def union(self, name: str, members: list[core.UnionMember] | None = None, attributes: list[str] | None = None) -> core.Union:

return core.Union(name, members, attributes)
97 changes: 89 additions & 8 deletions src/cfile/writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ class ElementType(Enum):
STRUCT_DECLARATION = 4 # Should this be separate from type declaration?
VARIABLE_DECLARATION = 5
FUNCTION_DECLARATION = 6
TYPEDEF = 7
TYPE_INSTANCE = 8
STRUCT_INSTANCE = 9
VARIABLE_USAGE = 10
FUNCTION_CALL = 11
STATEMENT = 12
BLOCK_START = 13
BLOCK_END = 14
UNION_DECLARATION = 7
TYPEDEF = 8
TYPE_INSTANCE = 9
STRUCT_INSTANCE = 10
UNION_INSTANCE = 11
VARIABLE_USAGE = 12
FUNCTION_CALL = 13
STATEMENT = 14
BLOCK_START = 15
BLOCK_END = 16


class Formatter:
Expand Down Expand Up @@ -123,6 +125,7 @@ def __init__(self, style: c_style.StyleOptions) -> None:
"IfndefDirective": self._write_ifndef_directive,
"EndifDirective": self._write_endif_directive,
"Extern": self._write_extern,
"Union": self._write_union_usage,
}
self.last_element = ElementType.NONE

Expand Down Expand Up @@ -282,6 +285,8 @@ def _write_declaration(self, elem: core.Declaration) -> None:
self._write_typedef_declaration(elem.element)
elif isinstance(elem.element, core.Struct):
self._write_struct_declaration(elem.element)
elif isinstance(elem.element, core.Union):
self._write_union_declaration(elem.element)
elif isinstance(elem.element, core.Variable):
self._write_variable_declaration(elem.element)
elif isinstance(elem.element, core.Function):
Expand Down Expand Up @@ -385,6 +390,8 @@ def _write_variable_declaration(self, elem: core.Variable) -> None:
self._write_type_declaration(elem.data_type)
elif isinstance(elem.data_type, core.Struct):
self._write_struct_usage(elem.data_type)
elif isinstance(elem.data_type, core.Union):
self._write_union_usage(elem.data_type)
elif isinstance(elem.data_type, core.Declaration):
self._write_declaration(elem.data_type)
elif isinstance(elem.data_type, core.TypeDef):
Expand Down Expand Up @@ -448,6 +455,8 @@ def _write_typedef_declaration(self, elem: core.TypeDef):
self._write_type_declaration(elem.base_type)
elif isinstance(elem.base_type, core.Struct):
self._write_struct_usage(elem.base_type)
elif isinstance(elem.base_type, core.Union):
self._write_union_usage(elem.base_type)
elif isinstance(elem.base_type, core.Declaration):
self._write_declaration(elem.base_type)
else:
Expand Down Expand Up @@ -509,6 +518,8 @@ def _write_function_declaration(self, elem: core.Function) -> None:
self._write_type_declaration(elem.return_type)
elif isinstance(elem.return_type, core.Struct):
self._write_struct_usage(elem.return_type)
elif isinstance(elem.return_type, core.Union):
self._write_union_usage(elem.return_type)
else:
raise NotImplementedError(str(type(elem.return_type)))
self._write(f" {elem.name}(")
Expand Down Expand Up @@ -641,6 +652,8 @@ def _write_struct_member(self, elem: core.StructMember) -> None:
self._write_type_declaration(elem.data_type)
elif isinstance(elem.data_type, core.Struct):
self._write_struct_usage(elem.data_type)
elif isinstance(elem.data_type, core.Union):
self._write_union_usage(elem.data_type)
else:
raise NotImplementedError(str(type(elem.data_type)))
result = ""
Expand Down Expand Up @@ -709,3 +722,71 @@ def _write_endif_directive(self, elem: core.EndifDirective) -> None:
def _write_extern(self, elem: core.Extern) -> None:
self._write(f'extern "{elem.language}"')
self.last_element = ElementType.DIRECTIVE

def _write_union_member(self, elem: core.UnionMember):
"""
Writes struct member
"""
if isinstance(elem.data_type, core.Type):
self._write_type_declaration(elem.data_type)
elif isinstance(elem.data_type, core.Struct):
self._write_struct_usage(elem.data_type)
elif isinstance(elem.data_type, core.Union):
self._write_union_usage(elem.data_type)
elif isinstance(elem.data_type, core.TypeDef):
self._write_typedef_usage(elem.data_type)
elif isinstance(elem.data_type, str):
self._write(elem.data_type)
else:
raise NotImplementedError(str(type(elem.data_type))+" "+ elem.name)
result = ""
if elem.pointer:
if self.style.pointer_alignment == c_style.Alignment.LEFT:
result += "* "
elif self.style.pointer_alignment == c_style.Alignment.RIGHT:
if isinstance(elem.data_type, core.Type) and elem.data_type.pointer:
result += "*"
else:
result += " *"
elif self.style.pointer_alignment == c_style.Alignment.MIDDLE:
result += " * "
else:
raise ValueError(self.style.pointer_alignment)
else:
if not (isinstance(elem.data_type, core.Type) and elem.data_type.pointer and (
self.style.pointer_alignment == c_style.Alignment.RIGHT)):
result += " "
result += elem.name
self._write(result)

def _write_union_usage(self, elem: core.Union):
"""
Writes union usage
"""
if not elem.name:
raise ValueError("union doesn't have a name. Did you mean to use a declaration?")
self._write(f"union {elem.name}")


def _write_union_declaration(self, elem: core.Union):
self._write(f"union {elem.name}")
if self.style.brace_wrapping.after_struct:
self._eol()
self._start_line()
self._write("{")
self._eol()
else:
self._write(" {")
self._eol()
if len(elem.members):
self._indent()
for member in elem.members:
self._start_line()
self._write_union_member(member)
self._write(";")
self._eol()
if len(elem.members):
self._dedent()
self._start_line()
self._write("}")
self.last_element = ElementType.UNION_DECLARATION

0 comments on commit 06506ef

Please sign in to comment.