Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address Issue with Array-Initialization -- Other General Cleanup #63

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions blark/iec.lark
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,8 @@ _array_spec_type: STRING_TYPE

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

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

array_initial_element: ( integer | enumerated_value ) "(" [ _array_initial_element ] ")" -> array_initial_element_count
| _array_initial_element
Expand Down Expand Up @@ -719,7 +718,6 @@ function_call: symbolic_variable "(" [ param_assignment ( "," param_assignment )
statement_list: _statement+

_statement: ";"
| method_statement
| assignment_statement
| no_op_statement
| set_statement
Expand Down Expand Up @@ -748,9 +746,6 @@ reset_statement: _variable "R="i expression ";"+

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

// method ::= expression [DEREFERENCED] '.' _identifier '(' ')';
method_statement: symbolic_variable "(" ")" DEREFERENCED? ";"+

// B.3.2.2
return_statement.1: "RETURN"i ";"*
// return_statement: priority > 0 so that it doesn't clash with no_op_statement
Expand Down
8 changes: 8 additions & 0 deletions blark/tests/source/array_with_integer_initializer.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{attribute 'hide'}
METHOD prv_Detection : BOOL
VAR_IN_OUT
currentChannel : ARRAY[*] OF someStruct := 0;
END_VAR

// do some stuff
END_METHOD
26 changes: 20 additions & 6 deletions blark/tests/test_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,16 @@ def roundtrip_rule(rule_name: str, value: str, expected: Optional[str] = None):
print(transformed)
if expected is None:
expected = value
assert str(transformed) == expected, \
"Transformed object does not produce identical source code"
try:
assert str(transformed) == expected, \
"Transformed object does not produce identical source code"
except Exception:
tree = parse_source_code(value, parser=parser, transform=False)
print("\n\nTransformation failure. The original source code was:")
print(value)
print("\n\nThe parse tree is:")
print(tree.pretty())
raise

conftest.check_serialization(
transformed, deserialize=True, require_same_source=True
Expand Down Expand Up @@ -63,6 +71,9 @@ def test_check_unhandled_rules(grammar):
# handled as aliases
"case_list",

# handled as special cases
"array_initialization",

# handled as tree
"global_var_list",
"var_body",
Expand Down Expand Up @@ -406,8 +417,6 @@ def test_input_roundtrip(rule_name, value):
END_VAR
""",
),
marks=pytest.mark.xfail(reason="TODO; this is valid grammar, I think"),
# Appears to collide with enum rule; need to fix
),
],
)
Expand Down Expand Up @@ -447,15 +456,20 @@ def test_output_roundtrip(rule_name, value):
END_VAR
"""
)),
param("input_output_declarations", tf.multiline_code_block(
"""
VAR_IN_OUT
fbProblematic1 : FB_Test(initializer := 5) := (A := 1, B := 2, C := 3);
END_VAR
"""
)),
param("input_output_declarations", tf.multiline_code_block(
"""
VAR_IN_OUT
fbTest : FB_Test := (A := 1, B := 2, C := 3);
END_VAR
""",
),
marks=pytest.mark.xfail(reason="TODO; this is valid grammar, I think"),
# Appears to collide with enum rule; need to fix
),
],
)
Expand Down
59 changes: 28 additions & 31 deletions blark/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -1226,19 +1226,32 @@ def from_lark(


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


@dataclass
@_rule_handler("bare_array_initialization")
class _BareArrayInitialization:
@staticmethod
def from_lark(*elements: ArrayInitialElement) -> ArrayInitialization:
return ArrayInitialization(list(elements))
return ArrayInitialization(list(elements), brackets=False)


@dataclass
class ArrayInitialization:
elements: List[ArrayInitialElement]
brackets: bool = False
meta: Optional[Meta] = meta_field()

def __str__(self) -> str:
elements = ", ".join(str(element) for element in self.elements)
return f"[{elements}]"
if self.brackets:
return f"[{elements}]"
return elements


@dataclass
Expand Down Expand Up @@ -1619,25 +1632,19 @@ def value(self) -> str:
@staticmethod
def from_lark(
name: SymbolicVariable,
first_parameter: Optional[ParameterAssignment] = None,
*remaining_parameters: ParameterAssignment,
*params: Union[ParameterAssignment, lark.Token, None],
) -> FunctionCall:
# Remove the Dereference Token if Present in the Remaining Parameters
dereferenced = False
if remaining_parameters:
if str(remaining_parameters[-1]) == "^":
dereferenced = True
remaining_parameters = remaining_parameters[:-1]
# Condition parameters (which may be `None`) to represent empty tuple
if first_parameter is None:
parameters = []
else:
parameters = [first_parameter] + list(remaining_parameters)
if params and params[0] is None:
params = params[1:]
dereferenced = bool(params and params[-1] == "^")
if dereferenced:
params = params[:-1]

return FunctionCall(
name=name,
parameters=parameters,
dereferenced=dereferenced
parameters=typing.cast(List[ParameterAssignment], list(params)),
dereferenced=dereferenced,
)

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


@dataclass
@_rule_handler("method_statement", comments=True)
class MethodStatement(Statement):
method: SymbolicVariable
meta: Optional[Meta] = meta_field()

def __str__(self):
return f"{self.method}();"


@dataclass
@_rule_handler("while_statement", comments=True)
class WhileStatement(Statement):
Expand Down