Skip to content

Commit

Permalink
ENH: add union support
Browse files Browse the repository at this point in the history
  • Loading branch information
klauer committed Jan 15, 2022
1 parent c2b209d commit 5384fa4
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 5 deletions.
9 changes: 6 additions & 3 deletions blark/iec.lark
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ data_type_declaration: "TYPE"i [ _type_declaration ] ";"* "END_TYPE"i ";"*

_type_declaration: array_type_declaration
| structure_type_declaration
| union_type_declaration
| string_type_declaration
| simple_type_declaration
| subrange_type_declaration
Expand Down Expand Up @@ -305,16 +306,18 @@ _array_initial_element: constant
| structure_initialization
| enumerated_value

structure_type_declaration: structure_type_name [ extends ] ":" [ indirection_type ] _structure_declaration
structure_type_declaration: structure_type_name [ extends ] ":" [ indirection_type ] "STRUCT"i ( structure_element_declaration ";"+ )* "END_STRUCT"i

initialized_structure_type_declaration: structure_type_name [ extends ] ":" initialized_structure

initialized_structure: structure_type_name ":=" structure_initialization

_structure_declaration: "STRUCT"i ( structure_element_declaration ";"+ )* "END_STRUCT"i ";"*

structure_element_declaration: structure_element_name [ incomplete_location ] ":" ( initialized_structure | array_spec_init | simple_spec_init | subrange_spec_init | enumerated_spec_init )

union_element_declaration: structure_element_name ":" ( array_specification | simple_specification | subrange_specification | enumerated_specification )

union_type_declaration: structure_type_name ":" "UNION"i ( union_element_declaration ";"+ )* "END_UNION"i ";"*

structure_initialization: "(" structure_element_initialization ( "," structure_element_initialization )* ")"

structure_element_initialization: constant
Expand Down
1 change: 1 addition & 0 deletions blark/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ def from_function_block(
@dataclass
class DataTypeSummary(Summary):
"""Summary representation of a single data type."""
# Note: structures only for now.
name: str
source_code: str
type: str
Expand Down
22 changes: 21 additions & 1 deletion blark/tests/test_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,7 @@ def test_incomplete_located_var_decls(rule_name, value):
STRUCT
xPLC_CnBitsValid : BOOL;
xPLC_CnBits : ARRAY [0..20] OF BYTE;
END_STRUCT;
END_STRUCT
END_TYPE
"""
)),
Expand Down Expand Up @@ -1030,6 +1030,26 @@ def test_incomplete_located_var_decls(rule_name, value):
END_TYPE
"""
)),
param("data_type_declaration", tf.multiline_code_block(
"""
TYPE TypeName :
UNION
intval : INT;
as_bytes : ARRAY [0..2] OF BYTE;
END_UNION
END_TYPE
"""
)),
param("data_type_declaration", tf.multiline_code_block(
"""
TYPE TypeName :
UNION
intval : INT;
enum : (iValue := 1, iValue2 := 2) INT;
END_UNION
END_TYPE
"""
)),
],
)
def test_data_type_declaration(rule_name, value):
Expand Down
68 changes: 67 additions & 1 deletion blark/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,65 @@ def __str__(self) -> str:
return f"{name_and_location} : {self.init};"


UnionElementSpecification = Union[
ArraySpecification,
lark.Token, # simple_specification
SubrangeSpecification,
EnumeratedSpecification,
]


@dataclass
@_rule_handler("union_element_declaration", comments=True)
class UnionElementDeclaration:
name: lark.Token
spec: UnionElementSpecification
meta: Optional[Meta] = meta_field()

@property
def variables(self) -> List[str]:
"""API compat"""
return [self.name]

def __str__(self) -> str:
return f"{self.name} : {self.spec};"


@dataclass
@_rule_handler("union_type_declaration", comments=True)
class UnionTypeDeclaration:
name: lark.Token
declarations: List[UnionElementDeclaration]
meta: Optional[Meta] = meta_field()

@staticmethod
def from_lark(name: lark.Token, *decls: UnionElementDeclaration):
return UnionTypeDeclaration(
name=name,
declarations=list(decls),
)

def __str__(self) -> str:
if not self.declarations:
decls = None
else:
decls = indent(
"\n".join(
str(decl) for decl in self.declarations
)
)

return "\n".join(
line for line in (
f"{self.name} :",
"UNION",
decls,
"END_UNION",
)
if line is not None
)


@dataclass
@_rule_handler("initialized_structure")
class InitializedStructure:
Expand Down Expand Up @@ -3141,9 +3200,16 @@ def __str__(self) -> str:
if not self.declaration:
return "TYPE\nEND_TYPE"

decl = indent(self.declaration).lstrip()
if not isinstance(
self.declaration, (StructureTypeDeclaration, UnionTypeDeclaration)
):
# note: END_STRUCT; END_UNION; result in "END_TYPE expected not ;"
decl = decl + ";"

return "\n".join(
(
"TYPE " + indent(f"{self.declaration};").lstrip(),
f"TYPE {decl}",
"END_TYPE",
)
)
Expand Down

0 comments on commit 5384fa4

Please sign in to comment.