Skip to content

Commit 6fae121

Browse files
committed
ENH: first pass at JMP and labeled statements
1 parent bc5a458 commit 6fae121

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed

blark/iec.lark

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ parenthesized_expression: "(" expression ")"
727727
| constant
728728

729729
// B.3.2
730-
statement_list: _statement+
730+
statement_list: _statement+ end_of_statement_list_label?
731731

732732
_statement: ";"
733733
| assignment_statement
@@ -745,6 +745,8 @@ _statement: ";"
745745
| repeat_statement
746746
| exit_statement
747747
| continue_statement
748+
| jmp_statement
749+
| labeled_statement
748750

749751

750752
// B.3.2.1
@@ -779,7 +781,29 @@ case_statement: "CASE"i expression "OF"i case_elements [ else_clause ] "END_CASE
779781

780782
case_elements: case_element+
781783

782-
case_element: case_list ":" [ statement_list ]
784+
case_element_statement_list: _case_element_statement+
785+
786+
// Specifically exclude labeled statements as they are aliased to case
787+
// statements themselves:
788+
_case_element_statement: ";"
789+
| assignment_statement
790+
| no_op_statement
791+
| set_statement
792+
| reset_statement
793+
| reference_assignment_statement
794+
| return_statement
795+
| chained_function_call_statement
796+
| function_call_statement
797+
| if_statement
798+
| case_statement
799+
| for_statement
800+
| while_statement
801+
| repeat_statement
802+
| exit_statement
803+
| continue_statement
804+
| jmp_statement
805+
806+
case_element: case_list ":" [ case_element_statement_list ]
783807

784808
case_list: case_list_element ( "," case_list_element )*
785809

@@ -804,3 +828,11 @@ repeat_statement: "REPEAT"i statement_list "UNTIL"i expression "END_REPEAT"i ";"
804828
exit_statement.1: "EXIT"i ";"+
805829

806830
continue_statement.1: "CONTINUE"i ";"+
831+
832+
LABEL: IDENTIFIER
833+
labeled_statement.1: LABEL ":" _statement
834+
835+
// End-of-statement list may have a label associated with it:
836+
end_of_statement_list_label: LABEL ":"
837+
838+
jmp_statement: "JMP"i LABEL ";"+

blark/tests/test_transformer.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,3 +1724,60 @@ def test_statement_priority(statement: str, cls: type):
17241724
assert isinstance(transformed, tf.StatementList)
17251725
transformed_statement, = transformed.statements
17261726
assert isinstance(transformed_statement, cls)
1727+
1728+
1729+
@pytest.mark.parametrize(
1730+
"statements, labels",
1731+
[
1732+
param(
1733+
tf.multiline_code_block(
1734+
"""
1735+
JMP _label;
1736+
_label :
1737+
""",
1738+
),
1739+
[],
1740+
id="simple_jump_no_statement"
1741+
),
1742+
param(
1743+
tf.multiline_code_block(
1744+
"""
1745+
JMP _label;
1746+
_label : A := 5;
1747+
""",
1748+
),
1749+
[],
1750+
id="simple_jump_with_assignment"
1751+
),
1752+
param(
1753+
tf.multiline_code_block(
1754+
"""
1755+
JMP _label;
1756+
_label :
1757+
IF a = 2 THEN
1758+
b := 3;
1759+
END_IF
1760+
""",
1761+
),
1762+
[],
1763+
id="simple_jump_with_assignment"
1764+
),
1765+
param(
1766+
tf.multiline_code_block(
1767+
"""
1768+
JMP _label1;
1769+
_label1 :
1770+
_label2 :
1771+
IF a = 2 THEN
1772+
b := 3;
1773+
END_IF
1774+
""",
1775+
),
1776+
[],
1777+
id="multi_label"
1778+
),
1779+
],
1780+
)
1781+
def test_labeled_statements_roundtrip(statements: str, labels: List[str]):
1782+
transformed = roundtrip_rule("statement_list", statements)
1783+
assert isinstance(transformed, tf.StatementList)

blark/transform.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3055,7 +3055,40 @@ def __str__(self) -> str:
30553055

30563056

30573057
@dataclass
3058-
@_rule_handler("statement_list")
3058+
@_rule_handler(
3059+
"labeled_statement",
3060+
"end_of_statement_list_label",
3061+
comments=True,
3062+
)
3063+
class LabeledStatement(Statement):
3064+
label: lark.Token
3065+
statement: Optional[Statement] = None
3066+
meta: Optional[Meta] = meta_field()
3067+
3068+
def __str__(self) -> str:
3069+
if self.statement is None:
3070+
return f"{self.label} :"
3071+
3072+
statement = str(self.statement)
3073+
if statement.count("\n") > 1:
3074+
# Multiline statement after label - put it on the next line
3075+
return f"{self.label} :\n{statement}"
3076+
# Single line statement after label - put it on the same line
3077+
return f"{self.label} : {statement}"
3078+
3079+
3080+
@dataclass
3081+
@_rule_handler("jmp_statement", comments=True)
3082+
class JumpStatement(Statement):
3083+
label: lark.Token
3084+
meta: Optional[Meta] = meta_field()
3085+
3086+
def __str__(self) -> str:
3087+
return f"JMP {self.label};"
3088+
3089+
3090+
@dataclass
3091+
@_rule_handler("statement_list", "case_element_statement_list")
30593092
class StatementList:
30603093
statements: List[Statement]
30613094
meta: Optional[Meta] = meta_field()

0 commit comments

Comments
 (0)