@@ -37,7 +37,13 @@ class Qasm:
3737 """Qasm stores the final result of the Qasm parsing."""
3838
3939 def __init__ (
40- self , supported_format : bool , qelib1_include : bool , qregs : dict , cregs : dict , c : Circuit
40+ self ,
41+ supported_format : bool ,
42+ qelib1_include : bool ,
43+ qregs : dict ,
44+ cregs : dict ,
45+ input_params : dict [str , str ],
46+ circuit : Circuit ,
4147 ):
4248 """Initializes Qasm.
4349
@@ -53,7 +59,8 @@ def __init__(
5359 self .supportedFormat = supported_format
5460 self .qregs = qregs
5561 self .cregs = cregs
56- self .circuit = c
62+ self .circuit = circuit
63+ self .input_params = input_params
5764
5865
5966def _generate_op_qubits (args : list [list [ops .Qid ]], lineno : int ) -> list [list [ops .Qid ]]:
@@ -187,24 +194,34 @@ def __init__(self) -> None:
187194 Attributes:
188195 gate_set: The gates available to use in the circuit, including those from
189196 libraries, and user-defined ones.
197+ circuit: A Cirq Circuit object.
198+ qregs: Quantum registers.
199+ cregs: Classical registers.
190200 in_custom_gate_scope: This is set to True when the parser is in the middle
191201 of parsing a custom gate definition.
192202 custom_gate_scoped_params: The params declared within the current custom
193203 gate definition. Empty if not in custom gate scope.
194204 custom_gate_scoped_qubits: The qubits declared within the current custom
195205 gate definition. Empty if not in custom gate scope.
206+ input_params: The input parameters mapped from name to type.
207+ qelibinc: Boolean indicating whether the Quantum Experience standard header
208+ is present or not.
209+ supported_format: Boolean indicating whether the format is supported.
210+ format_version: The OpenQASM version string.
196211 """
197212 self .parser = yacc .yacc (module = self , debug = False , write_tables = False )
198213 self .circuit = Circuit ()
199214 self .qregs : dict [str , int ] = {}
200215 self .cregs : dict [str , int ] = {}
201216 self .gate_set : dict [str , CustomGate | QasmGateStatement ] = {** self .basic_gates }
202- self .in_custom_gate_scope = False
217+ self .in_custom_gate_scope : bool = False
203218 self .custom_gate_scoped_params : set [str ] = set ()
204219 self .custom_gate_scoped_qubits : dict [str , ops .Qid ] = {}
205- self .qelibinc = False
220+ self .input_params : dict [str , str ] = {}
221+ self .qelibinc : bool = False
206222 self .lexer = QasmLexer ()
207- self .supported_format = False
223+ self .supported_format : bool = False
224+ self .format_version : str = ""
208225 self .parsedQasm : Qasm | None = None
209226 self .qubits : dict [str , ops .Qid ] = {}
210227 self .functions = {
@@ -810,7 +827,14 @@ def p_start(self, p):
810827 def p_qasm_format_only (self , p ):
811828 """qasm : format"""
812829 self .supported_format = True
813- p [0 ] = Qasm (self .supported_format , self .qelibinc , self .qregs , self .cregs , self .circuit )
830+ p [0 ] = Qasm (
831+ self .supported_format ,
832+ self .qelibinc ,
833+ self .qregs ,
834+ self .cregs ,
835+ self .input_params ,
836+ self .circuit ,
837+ )
814838
815839 def p_qasm_no_format_specified_error (self , p ):
816840 """qasm : QELIBINC
@@ -823,31 +847,49 @@ def p_qasm_include(self, p):
823847 """qasm : qasm QELIBINC"""
824848 self .qelibinc = True
825849 self .gate_set |= self .qelib_gates
826- p [0 ] = Qasm (self .supported_format , self .qelibinc , self .qregs , self .cregs , self .circuit )
850+ p [0 ] = Qasm (
851+ self .supported_format ,
852+ self .qelibinc ,
853+ self .qregs ,
854+ self .cregs ,
855+ self .input_params ,
856+ self .circuit ,
857+ )
827858
828859 def p_qasm_include_stdgates (self , p ):
829860 """qasm : qasm STDGATESINC"""
830861 self .qelibinc = True
831862 self .gate_set |= self .qelib_gates
832- p [0 ] = Qasm (self .supported_format , self .qelibinc , self .qregs , self .cregs , self .circuit )
863+ p [0 ] = Qasm (
864+ self .supported_format ,
865+ self .qelibinc ,
866+ self .qregs ,
867+ self .cregs ,
868+ self .input_params ,
869+ self .circuit ,
870+ )
833871
834872 def p_qasm_circuit (self , p ):
835873 """qasm : qasm circuit"""
836- p [0 ] = Qasm (self .supported_format , self .qelibinc , self .qregs , self .cregs , p [2 ])
874+ p [0 ] = Qasm (
875+ self .supported_format , self .qelibinc , self .qregs , self .cregs , self .input_params , p [2 ]
876+ )
837877
838878 def p_format (self , p ):
839879 """format : FORMAT_SPEC"""
840880 if p [1 ] not in ["2.0" , "3.0" ]:
841881 raise QasmException (
842- f"Unsupported OpenQASM version: { p [1 ]} , "
843- "only 2.0 and 3.0 are supported currently by Cirq"
882+ f"Unsupported OpenQASM version: { p [1 ]} . "
883+ "Only 2.0 and 3.0 are supported currently by Cirq"
844884 )
885+ self .format_version = p [1 ]
845886
846887 # circuit : new_reg circuit
847888 # | gate_op circuit
848889 # | measurement circuit
849890 # | reset circuit
850891 # | if circuit
892+ # | input_decl circuit
851893 # | empty
852894
853895 def p_circuit_reg (self , p ):
@@ -862,6 +904,10 @@ def p_circuit_gate_or_measurement_or_if(self, p):
862904 self .circuit .append (p [2 ])
863905 p [0 ] = self .circuit
864906
907+ def p_circuit_input_decl (self , p ):
908+ """circuit : input_decl circuit"""
909+ p [0 ] = self .circuit
910+
865911 def p_circuit_empty (self , p ):
866912 """circuit : empty"""
867913 p [0 ] = self .circuit
@@ -891,7 +937,7 @@ def p_new_reg(self, p):
891937 else :
892938 # QUBIT '[' NATURAL_NUMBER ']' ID ';'
893939 name , length = p [5 ], p [3 ]
894- if name in self .qregs . keys () or name in self .cregs . keys () :
940+ if name in self .qregs or name in self .cregs or name in self . input_params :
895941 raise QasmException (f"{ name } is already defined at line { p .lineno (2 )} " )
896942 if length == 0 :
897943 raise QasmException (f"Illegal, zero-length register '{ name } ' at line { p .lineno (4 )} " )
@@ -934,6 +980,34 @@ def p_params_single(self, p):
934980 """params : expr"""
935981 p [0 ] = [p [1 ]]
936982
983+ # input declarations (OpenQASM 3.0 only)
984+ # input_decl : INPUT input_type '[' NATURAL_NUMBER ']' ID ';'
985+
986+ def p_input_type (self , p ):
987+ """input_type : FLOAT
988+ | ANGLE
989+ """
990+ p [0 ] = p [1 ]
991+
992+ def p_input_decl (self , p ):
993+ """input_decl : INPUT input_type '[' NATURAL_NUMBER ']' ID ';'"""
994+ if self .format_version != "3.0" :
995+ raise QasmException (
996+ f"'input' modifier at line { p .lineno (1 )} is only supported in OpenQASM 3.0"
997+ )
998+ # INPUT input_type '[' NATURAL_NUMBER ']' ID ';'
999+ bit_width = p [4 ]
1000+ if bit_width == 0 :
1001+ raise QasmException (
1002+ f"Illegal bit width of zero for input '{ p [6 ]} ' at line { p .lineno (4 )} "
1003+ )
1004+ input_type = f"{ p [2 ]} [{ bit_width } ]"
1005+ name = p [6 ]
1006+ if name in self .input_params or name in self .qregs or name in self .cregs :
1007+ raise QasmException (f"{ name } is already defined at line { p .lineno (6 )} " )
1008+ self .input_params [name ] = input_type
1009+ p [0 ] = (name , input_type )
1010+
9371011 # expr : term
9381012 # | ID
9391013 # | func '(' expression ')'
@@ -946,10 +1020,11 @@ def p_expr_term(self, p):
9461020
9471021 def p_expr_identifier (self , p ):
9481022 """expr : ID"""
949- if not self .in_custom_gate_scope :
950- raise QasmException (f"Parameter '{ p [1 ]} ' in line { p .lineno (1 )} not supported" )
951- if p [1 ] not in self .custom_gate_scoped_params :
952- raise QasmException (f"Undefined parameter '{ p [1 ]} ' in line { p .lineno (1 )} '" )
1023+ if p [1 ] not in self .input_params :
1024+ if not self .in_custom_gate_scope :
1025+ raise QasmException (f"Parameter '{ p [1 ]} ' in line { p .lineno (1 )} not supported" )
1026+ if p [1 ] not in self .custom_gate_scoped_params :
1027+ raise QasmException (f"Undefined parameter '{ p [1 ]} ' in line { p .lineno (1 )} '" )
9531028 p [0 ] = sympy .Symbol (p [1 ])
9541029
9551030 def p_expr_parens (self , p ):
0 commit comments