diff --git a/src/cfile/core.py b/src/cfile/core.py index 74e8edf..3f215c5 100644 --- a/src/cfile/core.py +++ b/src/cfile/core.py @@ -1,7 +1,7 @@ """ cfile core """ -from typing import Union, Any +from typing import Any, Self class Element: @@ -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, @@ -185,10 +185,13 @@ class Enum(DataType): A enum definition """ - def __init__(self, name: str, members: list[EnumMember] = [], attributes: list[str] = []) -> None: + def __init__(self, name: str, members: list[EnumMember] | None = None, attributes: list[str] | None = None) -> None: super().__init__(name) - if isinstance(members, list): - self.members: list[EnumMember] = members.copy() + + if members == None: + self.members = [] + elif isinstance(members, list): + self.members = list(members) enumValue = -1 for enum in self.members: if enum.value == None: @@ -197,8 +200,14 @@ def __init__(self, name: str, members: list[EnumMember] = [], attributes: list[s else: enumValue = enum.value else: - raise TypeError('Invalid argument type for "elements"') - self.attributes = attributes.copy() + raise TypeError('Invalid argument type for "members"') + + if attributes == None: + self.attributes = [] + elif isinstance(attributes, list): + self.attributes: list[str] = list(attributes) + else: + raise TypeError('Invalid argument type for "attributes"') def append(self, member: EnumMember) -> None: """ @@ -236,13 +245,22 @@ class Struct(DataType): """ A struct definition """ - def __init__(self, name: str = "", members: list[StructMember] = [], attributes: list[str] = []) -> None: + def __init__(self, name: str = "", members: list[StructMember] | None = None, attributes: list[str] | None = None) -> None: super().__init__(name) - if isinstance(members, list): - self.members: list[StructMember] = members.copy() + + if members == None: + self.members = [] + elif isinstance(members, list): + self.members: list[StructMember] = list(members) else: - raise TypeError('Invalid argument type for "elements"') - self.attributes = attributes.copy() + raise TypeError('Invalid argument type for "members"') + + if attributes == None: + self.attributes = [] + elif isinstance(attributes, list): + self.attributes: list[str] = list(attributes) + else: + raise TypeError('Invalid argument type for "attributes"') def append(self, member: StructMember) -> None: """ @@ -266,46 +284,39 @@ 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, attributes: list[str] | 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: + if attributes == None: + self.attributes = [] + elif isinstance(attributes, list): + self.attributes: list[str] = list(attributes) + else: + raise TypeError('Invalid argument type for "attributes"') + + 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): @@ -357,7 +368,7 @@ def __init__(self, static: bool = False, const: bool = False, # const function (as seen in C++) extern: bool = False, - params: list[Variable] = []) -> None: + params: list[Variable] | None = None) -> None: self.name = name self.static = static self.const = const @@ -370,7 +381,11 @@ def __init__(self, self.return_type = Type("void") else: raise TypeError(str(type(return_type))) - self.params = params.copy() + + if isinstance(params, list): + self.params: list[Variable] = list(params) + else: + raise TypeError('Invalid argument type for "params"') def append(self, param: Variable) -> "Function": """ @@ -403,7 +418,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 @@ -451,6 +466,8 @@ def __init__(self, self.expression = "true" if expression else "false" elif isinstance(expression, (int, float)): self.expression = str(expression) + elif isinstance(expression, EnumMember): + self.expression = expression.name elif isinstance(expression, (str, Element)): self.expression = expression else: @@ -513,7 +530,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 | "Sequence"] = [] def __len__(self) -> int: return len(self.elements) @@ -542,20 +559,132 @@ class Block(Sequence): """ -class ConditionType(Enum): - IF = 0 - ELSE_IF = 1 - ELSE = 2 +class Condition(Block): + """ + A sequence for condition wrapped in braces + """ + + def __init__(self, condition: str): + super().__init__() + self.condition = condition -class Condition(Block): +class Conditions(Element): """ A condition wrapped in braces """ - def __init__(self, condition: str = "", type: ConditionType = ConditionType.ELSE): + + def __init__(self, conditions: list[Condition] | None = None): super().__init__() - self.condition = condition - self.type = type - if (condition and type == ConditionType.ELSE) or (not condition and type != ConditionType.ELSE): - raise Exception("Condition and type didn't match") + if conditions == None: + self.conditions = [] + elif isinstance(conditions, list): + self.conditions: list[Condition] = list(conditions) + else: + raise TypeError('Invalid argument type for "conditions"') + + def append(self, member: Condition) -> None: + """ + Appends new element to the conditions definition + """ + if not isinstance(member, Condition): + raise TypeError(f'Invalid type, expected "Condition", got {str(type(member))}') + self.conditions.append(member) + + +class SwitchCase(Block): + """ + A sequence for switch case wrapped in braces + """ + + def __init__(self, cases: list[int | EnumMember | str] | None = None): + """ + Empty values means default + """ + super().__init__() + + if cases == None: + self.cases = [] + elif isinstance(cases, list): + self.cases: list[int | EnumMember | str] = list(cases) + else: + raise TypeError('Invalid argument type for "cases"') + + +class Switch(Element): + """ + A sequence for switch case wrapped in braces + """ + + def __init__(self, switchVar: str | Variable, cases: list[SwitchCase] | None = None): + super().__init__() + + if switchVar == "" or not (isinstance(switchVar, str) or isinstance(switchVar, Variable)): + raise ValueError("switchVar cannot be empty ") + + self.switchVar = switchVar + + if cases == None: + self.cases = [] + elif isinstance(cases, list): + self.cases: list[SwitchCase] = list(cases) + else: + raise TypeError('Invalid argument type for "cases"') + + def append(self, case: SwitchCase) -> None: + """ + Appends new element to the conditions definition + """ + if not isinstance(case, SwitchCase): + raise TypeError(f'Invalid type, expected "SwitchCase", got {str(type(case))}') + self.cases.append(case) + + +class Break(Element): + """ + Adding break into block + """ + + +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) diff --git a/src/cfile/factory.py b/src/cfile/factory.py index 4723a86..37f43f9 100644 --- a/src/cfile/factory.py +++ b/src/cfile/factory.py @@ -120,7 +120,7 @@ def function(self, static: bool = False, const: bool = False, # This is not const of the return type extern: bool = False, - params: list[core.Variable] = []) -> core.Function: + params: list[core.Variable] | None = None) -> core.Function: """ New function """ @@ -147,8 +147,8 @@ def enum_member(self, def enum(self, name: str, - members: list[core.EnumMember] = [], - attributes: list[str] = []): + members: list[core.EnumMember] | None = None, + attributes: list[str] | None = None): """ New Enum """ @@ -156,7 +156,7 @@ def enum(self, def struct_member(self, name: str, - data_type: str | core.Type | core.Struct, + data_type: str | core.DataType, const: bool = False, # Pointer qualifier only pointer: bool = False, array: int | None = None) -> core.StructMember: @@ -167,8 +167,8 @@ def struct_member(self, def struct(self, name: str, - members: list[core.StructMember] = [], - attributes: list[str] = [] + members: list[core.StructMember] | None = None, + attributes: list[str] | None = None ) -> core.Struct: """ New Struct @@ -222,16 +222,15 @@ def str_literal(self, text: str) -> core.StringLiteral: def func_call(self, name: str, - args: list[arg_types] | arg_types | None = None) -> core.FunctionCall: + args: list[arg_types] | None = None) -> core.FunctionCall: """ New function call """ - if args is None: - return core.FunctionCall(name, None) - elif isinstance(args, list): - return core.FunctionCall(name, args) - else: - return core.FunctionCall(name, [args]) + if isinstance(name, core.Function): + if ((isinstance(name.params, list) or isinstance(args, list)) and len(name.params) != len(args)) or ((not name.params or not args) and name.params != args): + raise ValueError('Function declaration and function call params doesn\'t matched in size.') + name = name.name + return core.FunctionCall(name, args) def func_return(self, expression: int | float | str | core.Element) -> core.FunctionReturn: """ @@ -247,8 +246,36 @@ def declaration(self, """ return core.Declaration(element, init_value) - def condition(self, condition:str, type:core.ConditionType): + def condition(self, condition: str) -> core.Condition: """ New condition """ - return core.Condition(condition, type) + return core.Condition(condition) + + def conditions(self, conditions: list[core.Condition] | None = None) -> core.Conditions: + """ + New condition + """ + return core.Conditions(conditions) + + def switch_case(self, cases: list[int | core.EnumMember | str] | None = None) -> core.SwitchCase: + + return core.SwitchCase(cases) + + def switch(self, switchVar: str | core.Variable, cases: list[core.SwitchCase] | None = None) -> core.Switch: + + return core.Switch(switchVar, cases) + + 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) + + def breakBlock(self) -> core.Break: + """ + Adding break into block + """ + return core.Break() diff --git a/src/cfile/writer.py b/src/cfile/writer.py index ff6628e..da03695 100644 --- a/src/cfile/writer.py +++ b/src/cfile/writer.py @@ -21,14 +21,16 @@ class ElementType(Enum): STRUCT_DECLARATION = 5 # Should this be separate from type declaration? VARIABLE_DECLARATION = 6 FUNCTION_DECLARATION = 7 - TYPEDEF = 8 - TYPE_INSTANCE = 9 - STRUCT_INSTANCE = 10 - VARIABLE_USAGE = 11 - FUNCTION_CALL = 12 - STATEMENT = 13 - BLOCK_START = 14 - BLOCK_END = 15 + UNION_DECLARATION = 8 + TYPEDEF = 9 + TYPE_INSTANCE = 10 + STRUCT_INSTANCE = 11 + UNION_INSTANCE = 12 + VARIABLE_USAGE = 13 + FUNCTION_CALL = 14 + STATEMENT = 15 + BLOCK_START = 16 + BLOCK_END = 17 class Formatter: @@ -76,7 +78,7 @@ def _dedent(self): self.indentation_str = self.indentation_char * \ (self.indentation_level * self.indent_width) - def _start_line(self, indent:bool = True): + def _start_line(self, indent: bool = True): if indent: self.fh.write(self.indentation_str) else: @@ -128,7 +130,10 @@ def __init__(self, style: c_style.StyleOptions) -> None: "IfndefDirective": self._write_ifndef_directive, "EndifDirective": self._write_endif_directive, "Extern": self._write_extern, - "Condition": self._write_condition, + "Conditions": self._write_conditions, + "Switch": self._write_switch, + "Break": self._write_break, + "Union": self._write_union_usage, } self.last_element = ElementType.NONE @@ -188,15 +193,18 @@ def _write_sequence(self, sequence: core.Sequence) -> None: self._start_line() self._write_line_comment(elem) self._eol() - elif isinstance(elem, core.Condition): - self._start_line() - self._write_condition(elem) + elif isinstance(elem, core.Conditions): + self._write_conditions(elem) + elif isinstance(elem, core.Switch): + self._write_switch(elem) elif isinstance(elem, core.Block): self._start_line() self._write_block(elem) elif isinstance(elem, core.Line): self._start_line() self._write_line_element(elem) + elif isinstance(elem, core.Break): + self._write_break(elem) else: if isinstance(elem, core.Blank): self._start_line(False) @@ -296,6 +304,8 @@ def _write_declaration(self, elem: core.Declaration) -> None: self._write_enum_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): @@ -324,10 +334,14 @@ def _write_initializer_member(self, value: Any) -> None: """ Writes initializer member """ - if isinstance(value, int): + if isinstance(value, bool): + self._write(str(value).lower()) + elif isinstance(value, int): self._write(str(value)) elif isinstance(value, str): self._write(f'"{value}"') + elif isinstance(value, core.EnumMember): + self._write(f'{value.name}') else: raise NotImplementedError(str(type(value))) @@ -401,6 +415,8 @@ def _write_variable_declaration(self, elem: core.Variable) -> None: self._write_enum_usage(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): @@ -448,7 +464,7 @@ def _write_typedef_usage(self, elem: core.TypeDef): """ Writes typedef usage """ - if elem.name == "": + if not elem.name: raise ValueError("Typedef without name detected") self._write(elem.name) @@ -462,56 +478,65 @@ def _write_typedef_declaration(self, elem: core.TypeDef): self._write("const ") if isinstance(elem.base_type, core.Type): self._write_type_declaration(elem.base_type) + elif isinstance(elem.base_type, core.TypeDef): + self._write(elem.base_type.name) elif isinstance(elem.base_type, core.Enum): self._write_enum_usage(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) + baseType = elem.base_type + if isinstance(elem.base_type.element, core.Function): + baseType = core.Declaration(core.Function("(*"+elem.name+")", elem.base_type.element.return_type, elem.base_type.element.static, + elem.base_type.element.const, elem.base_type.element.extern, elem.base_type.element.params)) + self._write_declaration(baseType) else: raise NotImplementedError(str(type(elem.base_type))) - result = "" - if elem.pointer: - if elem.const: - if self.style.space_around_pointer_qualifiers == c_style.SpaceLocation.DEFAULT: + if not (isinstance(elem.base_type, core.Declaration) and isinstance(elem.base_type.element, core.Function)): + result = "" + if elem.pointer: + if elem.const: + if self.style.space_around_pointer_qualifiers == c_style.SpaceLocation.DEFAULT: + if self.style.pointer_alignment == c_style.Alignment.LEFT: + result += "* const " + elif self.style.pointer_alignment == c_style.Alignment.RIGHT: + result += "*const " + elif self.style.pointer_alignment == c_style.Alignment.MIDDLE: + result += " * const " + else: + raise ValueError(self.style.pointer_alignment) + else: + raise NotImplementedError("Only default space location supported for pointer qualifiers") + else: if self.style.pointer_alignment == c_style.Alignment.LEFT: - result += "* const " + result += "* " elif self.style.pointer_alignment == c_style.Alignment.RIGHT: - result += "*const " + if isinstance(elem.base_type, core.Type) and elem.base_type.pointer: + result += "*" + else: + result += " *" elif self.style.pointer_alignment == c_style.Alignment.MIDDLE: - result += " * const " + result += " * " else: raise ValueError(self.style.pointer_alignment) - else: - raise NotImplementedError("Only default space location supported for pointer qualifiers") else: - if self.style.pointer_alignment == c_style.Alignment.LEFT: - result += "* " - elif self.style.pointer_alignment == c_style.Alignment.RIGHT: - if isinstance(elem.base_type, core.Type) and elem.base_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.base_type, core.Type) and elem.base_type.pointer) and ( - self.style.pointer_alignment == c_style.Alignment.RIGHT)): - result += " " - assert elem.name is not None - result += elem.name - if elem.array is not None: - result += f"[{elem.array}]" - self._write(result) + if not ((isinstance(elem.base_type, core.Type) and elem.base_type.pointer) and ( + self.style.pointer_alignment == c_style.Alignment.RIGHT)): + result += " " + assert elem.name is not None + result += elem.name + if elem.array is not None: + result += f"[{elem.array}]" + self._write(result) self.last_element = ElementType.TYPEDEF def _write_function_usage(self, elem: core.Function) -> None: """ Writes function usage (name of the function) """ - if elem.name == "": + if not elem.name: raise ValueError("Function with no name detected") self._write(elem.name) @@ -525,12 +550,14 @@ def _write_function_declaration(self, elem: core.Function) -> None: self._write("static ") if isinstance(elem.return_type, core.Type): self._write_type_declaration(elem.return_type) - if isinstance(elem.return_type, core.TypeDef): + elif isinstance(elem.return_type, core.TypeDef): self._write_typedef_usage(elem.return_type) elif isinstance(elem.return_type, core.Enum): self._write_enum_usage(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}(") @@ -625,7 +652,7 @@ def _write_enum_usage(self, elem: core.Enum) -> None: """ Writes enum usage """ - if elem.name == "": + if not elem.name: raise ValueError("enum doesn't have a name. Did you mean to use a declaration?") self._write(f"enum {elem.name}") @@ -666,7 +693,7 @@ def _write_struct_usage(self, elem: core.Struct) -> None: """ Writes struct usage """ - if elem.name == "": + if not elem.name: raise ValueError("struct doesn't have a name. Did you mean to use a declaration?") self._write(f"struct {elem.name}") @@ -704,6 +731,10 @@ 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) + elif isinstance(elem.data_type, core.TypeDef): + self._write_typedef_usage(elem.data_type) else: raise NotImplementedError(str(type(elem.data_type))) result = "" @@ -773,11 +804,131 @@ def _write_extern(self, elem: core.Extern) -> None: self._write(f'extern "{elem.language}"') self.last_element = ElementType.DIRECTIVE - def _write_condition(self, elem:core.Condition) -> None: - if elem.type == core.ConditionType.IF: - self._write(f"if ({elem.condition})") - elif elem.type == core.ConditionType.ELSE_IF: - self._write(f"else if ({elem.condition})") - elif elem.type == core.ConditionType.ELSE: + def _write_conditions(self, elem: core.Conditions) -> None: + elseCondition = None + firstCondition = False + + for condition in elem.conditions: + if condition.condition == "": + if elseCondition == None: + elseCondition = condition + continue + else: + raise ValueError("Empty condition (else) can be defined only once.") + self._start_line() + if not firstCondition: + firstCondition = True + self._write(f"if ({condition.condition})") + else: + self._write(f"else if ({condition.condition})") + self._write_block(condition) + if elseCondition: + self._start_line() self._write(f"else") - self._write_block(elem) + self._write_block(elseCondition) + + def _write_switch(self, elem: core.Switch): + defaultCase = None + self._start_line() + if type(elem.switchVar) == core.Variable: + self._write(f"switch({elem.switchVar.name}){{") + else: + self._write(f"switch({elem.switchVar}){{") + self._eol() + self._indent() + for case in elem.cases: + if not case.cases: + if defaultCase == None: + defaultCase = case + continue + else: + raise ValueError("Empty case (default) can be defined only once.") + firstCase = False + for condition in case.cases: + if not firstCase: + firstCase = True + else: + self._write_line("") + self._eol() + self._start_line() + self._write(f"case {condition if type(condition) == int or type(condition) == str else condition.name}:") + self._write_block(case) + if defaultCase: + self._start_line() + self._write(f"default:") + self._write_block(defaultCase) + self._dedent() + self._start_line() + self._write("}") + self._eol() + + def _write_break(self, elem: core.Break): + self._write("break") + + 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{" ".join([' __attribute__(('+attribute+'))' for attribute in elem.attributes])} {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