Skip to content

Commit

Permalink
Add test to verify name mangling works for reserved keywords
Browse files Browse the repository at this point in the history
1. Created a new file for the reserved keywords
  • Loading branch information
atharva-satpute committed Jun 10, 2024
1 parent 54ff709 commit 3d477b0
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 75 deletions.
85 changes: 10 additions & 75 deletions src/autoqasm/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,65 +33,9 @@
import autoqasm.types as aq_types
from autoqasm import errors
from autoqasm.program.gate_calibrations import GateCalibration
from autoqasm.reserved_keywords import is_reserved_keyword
from autoqasm.types import QubitIdentifierType as Qubit

reserved_keywords = [
"angle",
"array",
"barrier",
"bit",
"bool",
"box",
"cal",
"case",
"complex",
"const",
"creg",
"ctrl",
"default",
"defcal",
"defcalgrammar",
"delay",
"duration",
"durationof",
"end",
"euler",
"extern",
"false",
"float",
"frame",
"gate",
"gphase",
"im",
"include",
"input",
"int",
"inv",
"let",
"OPENQASM",
"measure",
"mutable",
"negctrl",
"output",
"pi",
"port",
"pragma",
"qreg", # For backward compatibility
"qubit",
"readonly",
"reset",
"return",
"sizeof",
"stretch",
"switch",
"tau",
"true",
"U",
"uint",
"void",
"waveform",
]


def main(
func: Callable | None = None,
Expand Down Expand Up @@ -380,6 +324,12 @@ def _convert_subroutine(
with aq_program.build_program() as program_conversion_context:
oqpy_program = program_conversion_context.get_oqpy_program()

# Iterate over list of dictionary keys to avoid runtime error
for key in list(kwargs):
is_keyword, new_name = is_reserved_keyword(key)
if is_keyword:
kwargs[new_name] = kwargs.pop(key)

if f not in program_conversion_context.subroutines_processing:
# Mark that we are starting to process this function to short-circuit recursion
program_conversion_context.subroutines_processing.add(f)
Expand Down Expand Up @@ -457,19 +407,6 @@ def _convert_subroutine(
return program_conversion_context.return_variable


def is_reserved_keyword(name: str) -> bool:
"""
Method to check whether or not 'name' is a reserved keyword
Args:
name (str): Name of the variable to be checked
Returns:
bool: True, if 'name' is a reserved keyword, False otherwise
"""
return name in reserved_keywords


def _wrap_for_oqpy_subroutine(f: Callable, options: converter.ConversionOptions) -> Callable:
"""Wraps the given function into a callable expected by oqpy.subroutine.
Expand Down Expand Up @@ -516,12 +453,10 @@ def _func(*args, **kwargs) -> Any:
f'Parameter "{param.name}" for subroutine "{_func.__name__}" '
"is missing a required type hint."
)
# Check whether 'param.name' is a OpenQasm keyword
if is_reserved_keyword(param.name):
_name = f"{param.name}_"
# Check whether 'param.name' is a reserved keyword
is_keyword, _name = is_reserved_keyword(param.name)
if is_keyword:
_func.__annotations__.pop(param.name)
else:
_name = param.name

new_param = inspect.Parameter(
name=_name,
Expand Down
74 changes: 74 additions & 0 deletions src/autoqasm/reserved_keywords.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Permalink: https://github.com/openqasm/openqasm/blob/main/source/grammar/qasm3Lexer.g4
reserved_keywords = {
"angle",
"array",
"barrier",
"bit",
"bool",
"box",
"cal",
"case",
"complex",
"const",
"creg",
"ctrl",
"default",
"defcal",
"defcalgrammar",
"delay",
"duration",
"durationof",
"end",
"euler",
"extern",
"false",
"float",
"frame",
"gate",
"gphase",
"im",
"include",
"input",
"int",
"inv",
"let",
"OPENQASM",
"measure",
"mutable",
"negctrl",
"output",
"pi",
"port",
"pragma",
"qreg",
"qubit",
"readonly",
"reset",
"return",
"sizeof",
"stretch",
"switch",
"tau",
"true",
"U",
"uint",
"void",
"waveform",
}


def is_reserved_keyword(name: str) -> bool:
"""
Method to check whether or not 'name' is a reserved keyword
Args:
name (str): Name of the variable to be checked
Returns:
tuple[bool, str]: Returns a tuple containing a boolean indicating
whether the input 'name' is a reserved keyword and the modified name.
If 'name' is a reserved keyword, the modified name has an underscore
('_') appended to it; otherwise, it remains unchanged.
"""
is_keyword = name in reserved_keywords
return (is_keyword, f"{name}_" if is_keyword else name)
26 changes: 26 additions & 0 deletions test/unit_tests/autoqasm/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
the local simulator.
"""

import math

import pytest
from braket.devices import LocalSimulator
from braket.tasks.local_quantum_task import LocalQuantumTask
Expand Down Expand Up @@ -1266,3 +1268,27 @@ def test(int[32] a, int[32] b) {
test(2, 3);
test(4, 5);"""
assert main.build().to_ir() == expected


def test_subroutine_call_with_reserved_keyword():
"""Test that subroutine call works with reserved keyword as a variable name"""

@aq.subroutine
def make_input_state(input: int, theta: float):
rx(input, theta)
measure(input)

@aq.main(num_qubits=3)
def teleportation():
input, theta = 0, math.pi / 2
make_input_state(theta=theta, input=input)

expected = """OPENQASM 3.0;
def make_input_state(int[32] input_, float[64] theta) {
rx(theta) __qubits__[input_];
bit __bit_0__;
__bit_0__ = measure __qubits__[input_];
}
qubit[3] __qubits__;
make_input_state(0, 1.5707963267948966);"""
assert teleportation.build().to_ir() == expected

0 comments on commit 3d477b0

Please sign in to comment.