Skip to content

Commit 4ea1ea0

Browse files
authored
Merge pull request #63 from engineerjoe440/bugfix/array-initialization-with-zero
FIX: Address Issue with Array-Initialization and Other General Cleanup
2 parents 84d7350 + 1b62191 commit 4ea1ea0

File tree

4 files changed

+58
-44
lines changed

4 files changed

+58
-44
lines changed

blark/iec.lark

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -334,9 +334,8 @@ _array_spec_type: STRING_TYPE
334334

335335
object_initializer_array: function_block_type_name "[" structure_initialization ( "," structure_initialization )* "]"
336336

337-
array_initialization: "[" array_initial_element ( "," array_initial_element )* "]"
338-
// Removed to allow correct parsing of FB attribute assignment - JS - 20230410
339-
// | array_initial_element ( "," array_initial_element )*
337+
array_initialization: "[" array_initial_element ( "," array_initial_element )* "]" -> bracketed_array_initialization
338+
| array_initial_element ( "," array_initial_element )* -> bare_array_initialization
340339

341340
array_initial_element: ( integer | enumerated_value ) "(" [ _array_initial_element ] ")" -> array_initial_element_count
342341
| _array_initial_element
@@ -719,7 +718,6 @@ function_call: symbolic_variable "(" [ param_assignment ( "," param_assignment )
719718
statement_list: _statement+
720719

721720
_statement: ";"
722-
| method_statement
723721
| assignment_statement
724722
| no_op_statement
725723
| set_statement
@@ -748,9 +746,6 @@ reset_statement: _variable "R="i expression ";"+
748746

749747
reference_assignment_statement: _variable "REF="i expression ";"+
750748

751-
// method ::= expression [DEREFERENCED] '.' _identifier '(' ')';
752-
method_statement: symbolic_variable "(" ")" DEREFERENCED? ";"+
753-
754749
// B.3.2.2
755750
return_statement.1: "RETURN"i ";"*
756751
// return_statement: priority > 0 so that it doesn't clash with no_op_statement
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{attribute 'hide'}
2+
METHOD prv_Detection : BOOL
3+
VAR_IN_OUT
4+
currentChannel : ARRAY[*] OF someStruct := 0;
5+
END_VAR
6+
7+
// do some stuff
8+
END_METHOD

blark/tests/test_transformer.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,16 @@ def roundtrip_rule(rule_name: str, value: str, expected: Optional[str] = None):
2828
print(transformed)
2929
if expected is None:
3030
expected = value
31-
assert str(transformed) == expected, \
32-
"Transformed object does not produce identical source code"
31+
try:
32+
assert str(transformed) == expected, \
33+
"Transformed object does not produce identical source code"
34+
except Exception:
35+
tree = parse_source_code(value, parser=parser, transform=False)
36+
print("\n\nTransformation failure. The original source code was:")
37+
print(value)
38+
print("\n\nThe parse tree is:")
39+
print(tree.pretty())
40+
raise
3341

3442
conftest.check_serialization(
3543
transformed, deserialize=True, require_same_source=True
@@ -63,6 +71,9 @@ def test_check_unhandled_rules(grammar):
6371
# handled as aliases
6472
"case_list",
6573

74+
# handled as special cases
75+
"array_initialization",
76+
6677
# handled as tree
6778
"global_var_list",
6879
"var_body",
@@ -406,8 +417,6 @@ def test_input_roundtrip(rule_name, value):
406417
END_VAR
407418
""",
408419
),
409-
marks=pytest.mark.xfail(reason="TODO; this is valid grammar, I think"),
410-
# Appears to collide with enum rule; need to fix
411420
),
412421
],
413422
)
@@ -447,15 +456,20 @@ def test_output_roundtrip(rule_name, value):
447456
END_VAR
448457
"""
449458
)),
459+
param("input_output_declarations", tf.multiline_code_block(
460+
"""
461+
VAR_IN_OUT
462+
fbProblematic1 : FB_Test(initializer := 5) := (A := 1, B := 2, C := 3);
463+
END_VAR
464+
"""
465+
)),
450466
param("input_output_declarations", tf.multiline_code_block(
451467
"""
452468
VAR_IN_OUT
453469
fbTest : FB_Test := (A := 1, B := 2, C := 3);
454470
END_VAR
455471
""",
456472
),
457-
marks=pytest.mark.xfail(reason="TODO; this is valid grammar, I think"),
458-
# Appears to collide with enum rule; need to fix
459473
),
460474
],
461475
)

blark/transform.py

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,19 +1226,32 @@ def from_lark(
12261226

12271227

12281228
@dataclass
1229-
@_rule_handler("array_initialization")
1230-
class ArrayInitialization:
1231-
elements: List[ArrayInitialElement]
1232-
count: Optional[Union[EnumeratedValue, Integer]] = None
1233-
meta: Optional[Meta] = meta_field()
1229+
@_rule_handler("bracketed_array_initialization")
1230+
class _BracketedArrayInitialization:
1231+
@staticmethod
1232+
def from_lark(*elements: ArrayInitialElement) -> ArrayInitialization:
1233+
return ArrayInitialization(list(elements), brackets=True)
12341234

1235+
1236+
@dataclass
1237+
@_rule_handler("bare_array_initialization")
1238+
class _BareArrayInitialization:
12351239
@staticmethod
12361240
def from_lark(*elements: ArrayInitialElement) -> ArrayInitialization:
1237-
return ArrayInitialization(list(elements))
1241+
return ArrayInitialization(list(elements), brackets=False)
1242+
1243+
1244+
@dataclass
1245+
class ArrayInitialization:
1246+
elements: List[ArrayInitialElement]
1247+
brackets: bool = False
1248+
meta: Optional[Meta] = meta_field()
12381249

12391250
def __str__(self) -> str:
12401251
elements = ", ".join(str(element) for element in self.elements)
1241-
return f"[{elements}]"
1252+
if self.brackets:
1253+
return f"[{elements}]"
1254+
return elements
12421255

12431256

12441257
@dataclass
@@ -1619,25 +1632,19 @@ def value(self) -> str:
16191632
@staticmethod
16201633
def from_lark(
16211634
name: SymbolicVariable,
1622-
first_parameter: Optional[ParameterAssignment] = None,
1623-
*remaining_parameters: ParameterAssignment,
1635+
*params: Union[ParameterAssignment, lark.Token, None],
16241636
) -> FunctionCall:
1625-
# Remove the Dereference Token if Present in the Remaining Parameters
1626-
dereferenced = False
1627-
if remaining_parameters:
1628-
if str(remaining_parameters[-1]) == "^":
1629-
dereferenced = True
1630-
remaining_parameters = remaining_parameters[:-1]
16311637
# Condition parameters (which may be `None`) to represent empty tuple
1632-
if first_parameter is None:
1633-
parameters = []
1634-
else:
1635-
parameters = [first_parameter] + list(remaining_parameters)
1638+
if params and params[0] is None:
1639+
params = params[1:]
1640+
dereferenced = bool(params and params[-1] == "^")
1641+
if dereferenced:
1642+
params = params[:-1]
16361643

16371644
return FunctionCall(
16381645
name=name,
1639-
parameters=parameters,
1640-
dereferenced=dereferenced
1646+
parameters=typing.cast(List[ParameterAssignment], list(params)),
1647+
dereferenced=dereferenced,
16411648
)
16421649

16431650
def __str__(self) -> str:
@@ -2890,16 +2897,6 @@ def __str__(self):
28902897
return f"{variables} := {self.expression};"
28912898

28922899

2893-
@dataclass
2894-
@_rule_handler("method_statement", comments=True)
2895-
class MethodStatement(Statement):
2896-
method: SymbolicVariable
2897-
meta: Optional[Meta] = meta_field()
2898-
2899-
def __str__(self):
2900-
return f"{self.method}();"
2901-
2902-
29032900
@dataclass
29042901
@_rule_handler("while_statement", comments=True)
29052902
class WhileStatement(Statement):

0 commit comments

Comments
 (0)