Skip to content

Commit 73c2167

Browse files
Fix/ Statement copying in functions and added loop limit in for loops (#223)
* update visitor.py replaced deepcopy with shallow copy for function statements * update visitor.py, test_loop.py - Added max loop limit in for loop statements - Added test cases * update CHANGELOG.md * Update src/pyqasm/visitor.py * linting --------- Co-authored-by: Harshit Gupta <[email protected]>
1 parent 25eb7d4 commit 73c2167

File tree

3 files changed

+52
-3
lines changed

3 files changed

+52
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Types of changes:
2929
### Fixed
3030
- Fixed multiple axes error in circuit visualization of decomposable gates in `draw` method. ([#209](https://github.com/qBraid/pyqasm/pull/210))
3131
- Fixed depth calculation for decomposable gates by computing depth of each constituent quantum gate.([#211](https://github.com/qBraid/pyqasm/pull/211))
32+
- Optimized statement copying in `_visit_function_call` with shallow-copy fallback to deepcopy and added `max_loop_iters` loop‐limit check in for loops.([#223](https://github.com/qBraid/pyqasm/pull/223))
3233
### Dependencies
3334

3435
### Other

src/pyqasm/visitor.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,16 @@ def _visit_forin_loop(self, statement: qasm3_ast.ForInLoop) -> list[qasm3_ast.St
19241924
span=statement.span,
19251925
)
19261926

1927+
# Check if the loop range exceeds the maximum allowed iterations
1928+
if len(irange) > self._loop_limit:
1929+
raise_qasm3_error(
1930+
# pylint: disable-next=line-too-long
1931+
f"Loop range '{len(irange)-1}' exceeded max allowed '{self._loop_limit}' iterations",
1932+
err_type=LoopLimitExceededError,
1933+
error_node=statement,
1934+
span=statement.span,
1935+
)
1936+
19271937
i: Optional[Variable] # will store iteration Variable to update to loop scope
19281938

19291939
result = []
@@ -2068,9 +2078,12 @@ def _visit_function_call(
20682078
result = []
20692079
for function_op in subroutine_def.body:
20702080
if isinstance(function_op, qasm3_ast.ReturnStatement):
2071-
return_statement = copy.deepcopy(function_op)
2081+
return_statement = copy.copy(function_op)
20722082
break
2073-
result.extend(self.visit_statement(copy.deepcopy(function_op)))
2083+
try:
2084+
result.extend(self.visit_statement(copy.copy(function_op)))
2085+
except (TypeError, copy.Error):
2086+
result.extend(self.visit_statement(copy.deepcopy(function_op)))
20742087

20752088
return_value = None
20762089
if return_statement:

tests/qasm3/test_loop.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import pytest
2121

2222
from pyqasm.entrypoint import loads
23-
from pyqasm.exceptions import ValidationError
23+
from pyqasm.exceptions import LoopLimitExceededError, ValidationError
2424
from tests.utils import (
2525
check_single_qubit_gate_op,
2626
check_single_qubit_rotation_op,
@@ -332,3 +332,38 @@ def test_convert_qasm3_for_loop_unsupported_type(caplog):
332332

333333
assert "Error at line 9, column 16" in caplog.text
334334
assert 'for bit b in "001"' in caplog.text
335+
336+
337+
def test_for_loop_limit_exceeded():
338+
"""Test that exceeding the loop limit raises LoopLimitExceededError for for loops."""
339+
qasm_str = """
340+
OPENQASM 3.0;
341+
include "stdgates.inc";
342+
qubit[4] q;
343+
bit[4] c;
344+
345+
for int i in [0:1000] {
346+
h q[0];
347+
}
348+
"""
349+
result = loads(qasm_str)
350+
with pytest.raises(LoopLimitExceededError):
351+
result.unroll(max_loop_iters=100)
352+
353+
354+
def test_for_loop_discrete_set_limit_exceeded():
355+
"""Test that exceeding the loop limit raises LoopLimitExceededError
356+
for for loops with discrete sets."""
357+
qasm_str = """
358+
OPENQASM 3.0;
359+
include "stdgates.inc";
360+
qubit[4] q;
361+
bit[4] c;
362+
363+
for int i in {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} {
364+
h q[0];
365+
}
366+
"""
367+
result = loads(qasm_str)
368+
with pytest.raises(LoopLimitExceededError):
369+
result.unroll(max_loop_iters=10)

0 commit comments

Comments
 (0)