Skip to content

[BUG] dumps() emits extern calls without a semicolon, producing unparsable QASM #438

Description

@ryanhill1

Environment

  • pyqasm version: 1.2.0 (main @ 036ad4d)
  • Python version: 3.12
  • Operating system: macOS 15

What happened?

dumps() emits an extern function call without its terminating semicolon, so the generated
program is not valid OpenQASM and will not reparse.

import openqasm3, pyqasm

m = pyqasm.loads("""OPENQASM 3.0;
extern my_extern(int);
my_extern(3);
""")
m.unroll()
out = pyqasm.dumps(m)
print(out)
openqasm3.parse(out)
OPENQASM 3.0;
extern my_extern(int);
my_extern(3)
openqasm3.parser.QASM3ParsingError

With any statement following the call, the two run together on one line:

qubit[1] q;
my_extern(3)x q[0];      # line 5:12 no viable alternative at input 'my_extern(3)'

The cause is the node type, not the printer. The unrolled AST holds a bare FunctionCall
where a statement belongs:

>>> [type(s).__name__ for s in m.unrolled_ast.statements]
['ExternDeclaration', 'FunctionCall']

FunctionCall is an expression node, so openqasm3.printer renders it as an expression —
no semicolon, no line break. It should be wrapped in an ExpressionStatement.

Scope is narrow: only extern calls are affected. Subroutine calls and builtin calls both
round-trip correctly.

extern call        QASM3ParsingError   tail: ['qubit[1] q;', 'my_extern(3)x q[0];']
extern, no follow  QASM3ParsingError   tail: ['qubit[1] q;', 'my_extern(3)']
subroutine call    reparses OK         tail: ['x q[0];', 'x q[0];']
builtin call       reparses OK         tail: ['qubit[1] q;', 'x q[0];']

Suggestions (Optional)

Wrap the call in qasm3_ast.ExpressionStatement before it is appended to the output
statements — _handle_extern_function_cleanup (src/pyqasm/visitor.py:591) is where the
extern statement list is assembled.

Worth a round-trip assertion in the tests either way: openqasm3.parse(pyqasm.dumps(m)) over
the existing extern fixtures would have caught this, and would catch the same class of bug for
any other node that reaches the statement list unwrapped.

Found while reviewing #425, which touches the expression-statement path but does not cause or
fix this — it reproduces identically on main.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions