Skip to content

Commit

Permalink
Merge pull request #105 from klauer/repeated-structured-type-declarat…
Browse files Browse the repository at this point in the history
…ion-fails-to-parse

Repeated structured type declaration fails to parse
  • Loading branch information
klauer authored Jan 31, 2025
2 parents f694b3d + cbbbf7c commit 672c469
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 42 deletions.
2 changes: 1 addition & 1 deletion blark/iec.lark
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ structure_type_declaration: structure_type_name_declaration [ extends ] ":" [ in

initialized_structure: structure_type_name ":=" structure_initialization

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

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

Expand Down
25 changes: 13 additions & 12 deletions blark/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,18 +174,19 @@ def from_declaration(
result = {}

if isinstance(item, tf.StructureElementDeclaration):
result[item.name] = DeclarationSummary(
name=str(item.name),
item=item,
location=item.location.name if item.location else None,
block=block_header,
type=item.full_type_name, # TODO -> get_type_summary?
base_type=item.base_type_name,
value=str(item.value),
parent=parent.name if parent is not None else "",
filename=filename,
**Summary.get_meta_kwargs(item.meta),
)
for var in item.variables:
result[var.name] = DeclarationSummary(
name=str(var.name),
item=item,
location=str(var.location).replace("AT ", "") if var.location else None,
block=block_header,
type=item.full_type_name, # TODO -> get_type_summary?
base_type=item.base_type_name,
value=str(item.value),
parent=parent.name if parent is not None else "",
filename=filename,
**Summary.get_meta_kwargs(item.meta),
)
elif isinstance(item, tf.UnionElementDeclaration):
result[item.name] = DeclarationSummary(
name=str(item.name),
Expand Down
5 changes: 5 additions & 0 deletions blark/tests/source/repeated_declaration.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
TYPE someStruct :
STRUCT
AlertTimer, SignalBadTimer, QualityBadTimer : library.TPUDO;
END_STRUCT
END_TYPE
2 changes: 1 addition & 1 deletion blark/tests/test_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ def test_twincat_general(twincat_general_281: PlcProjectMetadata):
DeclarationCheck(
name="I_EcatMaster1",
base_type="AMSNETID",
location="input",
location="%I*",
comments=[
"{attribute 'naming' := 'omit'}",
"(* AMS Net ID used for FB_EcatDiag, among others *)"
Expand Down
1 change: 1 addition & 0 deletions blark/tests/test_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ def test_bool_literal_roundtrip(name, value, expected):
param("var1_init_decl", "stVar1, stVar2 : TypeName := Value"),
param("var1_init_decl", "stVar1, stVar2 : (Value1 := 1, Value2 := 2)"),
param("var1_init_decl", "stVar1, stVar2 : (Value1 := 1, Value2 := 2) INT := Value1"),
param("structure_element_declaration", "Name1, Name2 : INT"),
param("structure_type_declaration", "TypeName :\nSTRUCT\nEND_STRUCT"),
param("structure_type_declaration", "TypeName EXTENDS Other.Type :\nSTRUCT\nEND_STRUCT"),
param("structure_type_declaration", "TypeName : POINTER TO\nSTRUCT\nEND_STRUCT"),
Expand Down
50 changes: 22 additions & 28 deletions blark/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -1924,7 +1924,7 @@ def __str__(self) -> str:
body = "\n".join(
(
"STRUCT",
indent("\n".join(str(decl) for decl in self.declarations)),
indent("\n".join(f"{decl};" for decl in self.declarations)),
"END_STRUCT",
)
)
Expand All @@ -1940,24 +1940,25 @@ def __str__(self) -> str:
@_rule_handler("structure_element_declaration", comments=True)
class StructureElementDeclaration:
"""
Declaration of a single element of a structure.
Declaration line of a structure, typically with a single variable name.
Excludes the trailing semicolon.
Examples::
iValue : INT := 3 + 4;
stTest : ST_Testing := (1, 2);
eValue : E_Test := E_Test.ABC;
arrValue : ARRAY [1..2] OF INT := [1, 2];
arrValue1 : INT (1..2);
arrValue1 : (Value1 := 1) INT;
sValue : STRING := 'abc';
iValue1 AT %I* : INT := 5;
sValue1 : STRING[10] := 'test';
iValue : INT := 3 + 4
stTest : ST_Testing := (1, 2)
eValue : E_Test := E_Test.ABC
arrValue : ARRAY [1..2] OF INT := [1, 2]
arrValue1 : INT (1..2)
arrValue1 : (Value1 := 1) INT
sValue : STRING := 'abc'
iValue1 AT %I* : INT := 5
sValue1 : STRING[10] := 'test'
Timer1, Timer2, Timer3 : library.TPUDO
"""
name: lark.Token
location: Optional[IncompleteLocation]
variables: List[DeclaredVariable]
init: Union[
StructureInitialization,
ArrayTypeInitialization,
StringTypeInitialization,
TypeInitialization,
Expand All @@ -1968,35 +1969,24 @@ class StructureElementDeclaration:
]
meta: Optional[Meta] = meta_field()

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

@property
def value(self) -> str:
"""The initialization value, if applicable."""
if isinstance(self.init, StructureInitialization):
return str(self.init)
return str(self.init.value)

@property
def base_type_name(self) -> Union[lark.Token, str]:
"""The base type name."""
if isinstance(self.init, StructureInitialization):
return self.name
return self.init.base_type_name

@property
def full_type_name(self) -> lark.Token:
def full_type_name(self) -> Union[lark.Token, str]:
"""The full type name."""
if isinstance(self.init, StructureInitialization):
return self.name
return self.init.full_type_name

def __str__(self) -> str:
name_and_location = join_if(self.name, " ", self.location)
return f"{name_and_location} : {self.init};"
variables = ", ".join(str(var) for var in self.variables)
return f"{variables} : {self.init}"


UnionElementSpecification = Union[
Expand Down Expand Up @@ -4585,6 +4575,10 @@ def full_subrange(self):
def var1_list(self, *items: DeclaredVariable) -> List[DeclaredVariable]:
return list(items)

@_annotator_method_wrapper
def struct_var1_list(self, *items: DeclaredVariable) -> List[DeclaredVariable]:
return list(items)

@_annotator_method_wrapper
def fb_decl_name_list(self, *items: lark.Token) -> List[lark.Token]:
return list(items)
Expand Down

0 comments on commit 672c469

Please sign in to comment.