Repository: Quantomatic/pyzx

Issue:
behaviour of `qasmparser` is unclear when `parse` is called multiple times
It's unclear how to use `qasmparser` if there are multiple strings or circuits to be parsed. In particular, `parse` has behaviour which is surprising to me. I expect each call to basically be independent and return a circuit based on the input string. What actually happens is `parse` builds on top of the circuit processed in previous calls.

In particular, it looks to me like [this line](https://github.com/Quantomatic/pyzx/blob/master/pyzx/circuit/qasmparser.py#L65) is intended to clear the previous state, but is bugged because `gates` rather than `self.gates` is used. 

Repro case:
```
from pyzx.circuit.qasmparser import QASMParser
s = """
OPENQASM 2;
include "qelib1.inc";
qreg q[1];
h q[0];
"""
p = QASMParser()
c1 = p.parse(s)
c2 = p.parse(s)
print(c1)
print(c1.gates)
print(c2)
print(c2.gates)
```

Expected output:
```
Circuit(1 qubits, 0 bits, 1 gates)
[HAD(0)]
Circuit(1 qubits, 0 bits, 1 gates)
[HAD(0)]
```

Actual output:
```
Circuit(1 qubits, 0 bits, 2 gates)
[HAD(0), HAD(1)]
Circuit(2 qubits, 0 bits, 2 gates)
[HAD(0), HAD(1)]
```

In particular, it is surprising that a subsequent call to `parse` alters the value of `c1`.

Discussion:

Patch:
diff --git a/pyzx/circuit/qasmparser.py b/pyzx/circuit/qasmparser.py
index b74cfa18..a4cb5cee 100644
--- a/pyzx/circuit/qasmparser.py
+++ b/pyzx/circuit/qasmparser.py
@@ -33,6 +33,11 @@ class QASMParser(object):
         self.circuit: Optional[Circuit] = None
 
     def parse(self, s: str, strict:bool=True) -> Circuit:
+        self.gates = []
+        self.customgates = {}
+        self.registers = {}
+        self.qubit_count = 0
+        self.circuit = None
         lines = s.splitlines()
         r = []
         #strip comments
@@ -62,7 +67,6 @@ class QASMParser(object):
             data = data[:i] + data[j+1:]
         #parse the regular commands
         commands = [s.strip() for s in data.split(";") if s.strip()]
-        gates: List[Gate] = []
         for c in commands:
             self.gates.extend(self.parse_command(c, self.registers))
 


Test patch:
diff --git a/tests/test_circuit.py b/tests/test_circuit.py
index edbbe0dc..79dfe25d 100644
--- a/tests/test_circuit.py
+++ b/tests/test_circuit.py
@@ -122,5 +122,20 @@ class TestCircuit(unittest.TestCase):
         self.assertTrue(c1.verify_equality(c2,up_to_swaps=True))
         self.assertFalse(c1.verify_equality(c2,up_to_swaps=False))
 
+    def test_parser_state_reset(self):
+        from pyzx.circuit.qasmparser import QASMParser
+        s = """
+        OPENQASM 2.0;
+        include "qelib1.inc";
+        qreg q[1];
+        h q[0];
+        """
+        p = QASMParser()
+        c1 = p.parse(s)
+        c2 = p.parse(s)
+        self.assertEqual(c2.qubits, 1)
+        self.assertEqual(len(c2.gates), 1)
+        self.assertTrue(c1.verify_equality(c2))
+
 if __name__ == '__main__':
-    unittest.main()
\ No newline at end of file
+    unittest.main()