diff --git a/crates/oq3_parser/src/grammar.rs b/crates/oq3_parser/src/grammar.rs index 51ef05c..dd34979 100644 --- a/crates/oq3_parser/src/grammar.rs +++ b/crates/oq3_parser/src/grammar.rs @@ -201,4 +201,8 @@ impl SyntaxKind { pub fn is_type(&self) -> bool { self.is_classical_type() || self.is_quantum_type() } + + pub fn is_creg_or_qreg(&self) -> bool { + matches!(self, T![qreg] | T![creg]) + } } diff --git a/crates/oq3_parser/src/grammar/expressions.rs b/crates/oq3_parser/src/grammar/expressions.rs index 3075ee7..54c0a75 100644 --- a/crates/oq3_parser/src/grammar/expressions.rs +++ b/crates/oq3_parser/src/grammar/expressions.rs @@ -148,24 +148,30 @@ pub(crate) fn stmt(p: &mut Parser<'_>) { } } -fn q_or_c_reg_declaration(p: &mut Parser<'_>, m: Marker) { - p.bump_any(); +/// The designator is on the identifier, rather than the type +/// in OQ2. So we don't parse the identifier and type separately +/// as we do for OQ3 constructions. +pub fn q_or_c_reg_param(p: &mut Parser<'_>) { + let m = p.start(); + p.bump_any(); // creg or qreg if !p.at(IDENT) { p.error("Expected qubit register name"); m.abandon(p); return; } - let m1 = p.start(); p.bump_any(); if p.at(T!['[']) && !p.at(EOF) { index_operator(p); } else { p.error("Expected index operator"); - m1.abandon(p); m.abandon(p); return; } - m1.complete(p, INDEXED_IDENTIFIER); + m.complete(p, OLD_TYPED_PARAM); +} + +fn q_or_c_reg_declaration(p: &mut Parser<'_>, m: Marker) { + q_or_c_reg_param(p); p.expect(T![;]); m.complete(p, OLD_STYLE_DECLARATION_STATEMENT); } diff --git a/crates/oq3_parser/src/grammar/params.rs b/crates/oq3_parser/src/grammar/params.rs index d6c9115..cd125be 100644 --- a/crates/oq3_parser/src/grammar/params.rs +++ b/crates/oq3_parser/src/grammar/params.rs @@ -154,7 +154,11 @@ fn _param_list_openqasm(p: &mut Parser<'_>, flavor: DefFlavor) { // Allowed starts for an item: either a type or a first-token of a param/expression, // or first token of array literal. if matches!(flavor, DefParams) && (p.at(T![mutable]) || p.at(T![readonly])) { - } else if !(p.current().is_type() || p.at_ts(PARAM_FIRST) || inner_array_literal) { + } else if !(p.current().is_type() + || p.at_ts(PARAM_FIRST) + || inner_array_literal + || p.current().is_creg_or_qreg()) + { p.error("expected value parameter"); m.abandon(p); break; @@ -294,6 +298,11 @@ fn param_untyped_or_hardware_qubit(p: &mut Parser<'_>, m: Marker) -> bool { /// Parse one parameter in the list of parameters in the signature /// of a subroutine defintion (that is, a `def` statement) fn param_typed(p: &mut Parser<'_>, m: Marker) -> bool { + if p.at(T![creg]) || p.at(T![qreg]) { + m.abandon(p); + expressions::q_or_c_reg_param(p); + return true; + } expressions::param_type_spec(p); expressions::var_name(p); m.complete(p, TYPED_PARAM); diff --git a/crates/oq3_parser/src/syntax_kind/syntax_kind_enum.rs b/crates/oq3_parser/src/syntax_kind/syntax_kind_enum.rs index 6696685..f750dda 100644 --- a/crates/oq3_parser/src/syntax_kind/syntax_kind_enum.rs +++ b/crates/oq3_parser/src/syntax_kind/syntax_kind_enum.rs @@ -191,6 +191,7 @@ pub enum SyntaxKind { RANGE_EXPR, TYPE, TYPED_PARAM, + OLD_TYPED_PARAM, TYPED_PARAM_LIST, TYPE_LIST, VERSION, diff --git a/crates/oq3_semantics/src/syntax_to_semantics.rs b/crates/oq3_semantics/src/syntax_to_semantics.rs index e4d0370..dac2615 100644 --- a/crates/oq3_semantics/src/syntax_to_semantics.rs +++ b/crates/oq3_semantics/src/syntax_to_semantics.rs @@ -1471,7 +1471,13 @@ fn bind_typed_parameter_list( param_list .typed_params() .map(|param| { - let typ = param_type_to_type(¶m.param_type().unwrap(), false, context); + let typ = if let Some(pt) = param.param_type() { + param_type_to_type(&pt, false, context) + } else if param.old_typed_param().is_some() { + Type::ToDo + } else { + panic!("You have found a bug in oq3_parser") + }; let namestr = param.name().unwrap().string(); context.new_binding(namestr.as_ref(), &typ, ¶m) }) diff --git a/crates/oq3_syntax/build.rs b/crates/oq3_syntax/build.rs index 7642382..976d275 100644 --- a/crates/oq3_syntax/build.rs +++ b/crates/oq3_syntax/build.rs @@ -446,6 +446,7 @@ mod sourcegen { "RANGE_EXPR", "TYPE", "TYPED_PARAM", + "OLD_TYPED_PARAM", "TYPED_PARAM_LIST", "TYPE_LIST", "VERSION", diff --git a/crates/oq3_syntax/openqasm3.ungram b/crates/oq3_syntax/openqasm3.ungram index 99ceded..3591cfa 100644 --- a/crates/oq3_syntax/openqasm3.ungram +++ b/crates/oq3_syntax/openqasm3.ungram @@ -195,7 +195,10 @@ ParamType = (ScalarType | ArrayRefType) TypedParam = - ParamType Name + (ParamType Name) | OldTypedParam + +OldTypedParam = + ('creg' | 'qreg') Name Designator? TypedParamList = '(' (TypedParam (',' TypedParam)* ','?)? ')' @@ -446,7 +449,7 @@ IODeclarationStatement = ('input' | 'output') (ScalarType | ArrayType) Name ';' OldStyleDeclarationStatement = - ('creg' | 'qreg') Name Designator? ';' + OldTypedParam ';' QuantumDeclarationStatement = QubitType (Name | HardwareQubit) ';' diff --git a/crates/oq3_syntax/src/ast/generated/nodes.rs b/crates/oq3_syntax/src/ast/generated/nodes.rs index 63727c0..8b321d0 100644 --- a/crates/oq3_syntax/src/ast/generated/nodes.rs +++ b/crates/oq3_syntax/src/ast/generated/nodes.rs @@ -405,15 +405,8 @@ impl Measure { pub struct OldStyleDeclarationStatement { pub(crate) syntax: SyntaxNode, } -impl ast::HasName for OldStyleDeclarationStatement {} impl OldStyleDeclarationStatement { - pub fn creg_token(&self) -> Option { - support::token(&self.syntax, T![creg]) - } - pub fn qreg_token(&self) -> Option { - support::token(&self.syntax, T![qreg]) - } - pub fn designator(&self) -> Option { + pub fn old_typed_param(&self) -> Option { support::child(&self.syntax) } pub fn semicolon_token(&self) -> Option { @@ -761,6 +754,25 @@ impl TypedParam { pub fn param_type(&self) -> Option { support::child(&self.syntax) } + pub fn old_typed_param(&self) -> Option { + support::child(&self.syntax) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct OldTypedParam { + pub(crate) syntax: SyntaxNode, +} +impl ast::HasName for OldTypedParam {} +impl OldTypedParam { + pub fn creg_token(&self) -> Option { + support::token(&self.syntax, T![creg]) + } + pub fn qreg_token(&self) -> Option { + support::token(&self.syntax, T![qreg]) + } + pub fn designator(&self) -> Option { + support::child(&self.syntax) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ArrayExpr { @@ -1955,6 +1967,21 @@ impl AstNode for TypedParam { &self.syntax } } +impl AstNode for OldTypedParam { + fn can_cast(kind: SyntaxKind) -> bool { + kind == OLD_TYPED_PARAM + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} impl AstNode for ArrayExpr { fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_EXPR @@ -3037,10 +3064,10 @@ impl AstNode for AnyHasName { | GATE | I_O_DECLARATION_STATEMENT | LET_STMT - | OLD_STYLE_DECLARATION_STATEMENT | QUANTUM_DECLARATION_STATEMENT | PARAM | TYPED_PARAM + | OLD_TYPED_PARAM | GATE_CALL_EXPR | HARDWARE_QUBIT | INDEXED_IDENTIFIER @@ -3318,6 +3345,11 @@ impl std::fmt::Display for TypedParam { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for OldTypedParam { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for ArrayExpr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__invalid__statements__io.qasm-parse.snap b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__invalid__statements__io.qasm-parse.snap index 80799b4..93fdd64 100644 --- a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__invalid__statements__io.qasm-parse.snap +++ b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__invalid__statements__io.qasm-parse.snap @@ -33,7 +33,7 @@ I_O_DECLARATION_STATEMENT@30..36: input SCALAR_TYPE@36..36: NAME@36..36: OLD_STYLE_DECLARATION_STATEMENT@36..50: qreg myvar[4]; -INDEXED_IDENTIFIER@41..49: myvar[4] +OLD_TYPED_PARAM@36..49: qreg myvar[4] INDEX_OPERATOR@46..49: [4] EXPRESSION_LIST@47..48: 4 LITERAL@47..48: 4 @@ -41,7 +41,7 @@ I_O_DECLARATION_STATEMENT@51..58: output SCALAR_TYPE@58..58: NAME@58..58: OLD_STYLE_DECLARATION_STATEMENT@58..72: qreg myvar[4]; -INDEXED_IDENTIFIER@63..71: myvar[4] +OLD_TYPED_PARAM@58..71: qreg myvar[4] INDEX_OPERATOR@68..71: [4] EXPRESSION_LIST@69..70: 4 LITERAL@69..70: 4 diff --git a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__invalid__statements__measure.qasm-parse.snap b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__invalid__statements__measure.qasm-parse.snap index 265aa69..69283ff 100644 --- a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__invalid__statements__measure.qasm-parse.snap +++ b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__invalid__statements__measure.qasm-parse.snap @@ -49,7 +49,7 @@ ERROR@58..59: > EXPR_STMT@60..62: b; IDENTIFIER@60..61: b OLD_STYLE_DECLARATION_STATEMENT@63..72: creg a[1] -INDEXED_IDENTIFIER@68..72: a[1] +OLD_TYPED_PARAM@63..72: creg a[1] INDEX_OPERATOR@69..72: [1] EXPRESSION_LIST@70..71: 1 LITERAL@70..71: 1 @@ -63,7 +63,7 @@ MEASURE_EXPRESSION@87..97: measure $0 HARDWARE_QUBIT@95..97: $0 ERROR@99..100: > OLD_STYLE_DECLARATION_STATEMENT@101..111: creg a[1]; -INDEXED_IDENTIFIER@106..110: a[1] +OLD_TYPED_PARAM@101..110: creg a[1] INDEX_OPERATOR@107..110: [1] EXPRESSION_LIST@108..109: 1 LITERAL@108..109: 1 diff --git a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__assignment__alias.qasm-parse.snap b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__assignment__alias.qasm-parse.snap index af8dece..22289f7 100644 --- a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__assignment__alias.qasm-parse.snap +++ b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__assignment__alias.qasm-parse.snap @@ -27,7 +27,7 @@ DESIGNATOR@4..7: [2] LITERAL@5..6: 2 NAME@8..9: a OLD_STYLE_DECLARATION_STATEMENT@11..21: creg b[2]; -INDEXED_IDENTIFIER@16..20: b[2] +OLD_TYPED_PARAM@11..20: creg b[2] INDEX_OPERATOR@17..20: [2] EXPRESSION_LIST@18..19: 2 LITERAL@18..19: 2 @@ -37,7 +37,7 @@ DESIGNATOR@27..30: [5] LITERAL@28..29: 5 NAME@31..33: q1 OLD_STYLE_DECLARATION_STATEMENT@35..46: qreg q2[7]; -INDEXED_IDENTIFIER@40..45: q2[7] +OLD_TYPED_PARAM@35..45: qreg q2[7] INDEX_OPERATOR@42..45: [7] EXPRESSION_LIST@43..44: 7 LITERAL@43..44: 7 diff --git a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__assignment__assignment.qasm-parse.snap b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__assignment__assignment.qasm-parse.snap index 44c624d..66ff10f 100644 --- a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__assignment__assignment.qasm-parse.snap +++ b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__assignment__assignment.qasm-parse.snap @@ -33,7 +33,7 @@ DESIGNATOR@14..17: [2] LITERAL@15..16: 2 NAME@18..19: b OLD_STYLE_DECLARATION_STATEMENT@21..31: creg b[2]; -INDEXED_IDENTIFIER@26..30: b[2] +OLD_TYPED_PARAM@21..30: creg b[2] INDEX_OPERATOR@27..30: [2] EXPRESSION_LIST@28..29: 2 LITERAL@28..29: 2 diff --git a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__subroutine__subroutine.qasm-parse.snap b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__subroutine__subroutine.qasm-parse.snap index 4c521e3..4f1ad24 100644 --- a/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__subroutine__subroutine.qasm-parse.snap +++ b/crates/pipeline-tests/tests/snapshots/runner__tests__snippets__reference__subroutine__subroutine.qasm-parse.snap @@ -3,11 +3,11 @@ source: crates/pipeline-tests/tests/runner.rs expression: parse_snap --- id: tests/snippets/reference/subroutine/subroutine.qasm -expect-parse: Todo +expect-parse: Ok --- parser --- -ok: false +ok: true panicked: false -errors: 14 +errors: 0 --- ast --- SOURCE_FILE@0..293: def test_sub1(int[5] i, qubit[2] q1, qreg q2[5]) -> int[10] { @@ -24,9 +24,13 @@ def returns_a_measure(qubit q) { return measure q; } -DEF@1..37: def test_sub1(int[5] i, qubit[2] q1, +DEF@1..137: def test_sub1(int[5] i, qubit[2] q1, qreg q2[5]) -> int[10] { + int[10] result; + if (result == 2) return 1 + result; + return result; +} NAME@5..14: test_sub1 -TYPED_PARAM_LIST@14..37: (int[5] i, qubit[2] q1, +TYPED_PARAM_LIST@14..49: (int[5] i, qubit[2] q1, qreg q2[5]) TYPED_PARAM@15..23: int[5] i SCALAR_TYPE@15..21: int[5] DESIGNATOR@18..21: [5] @@ -37,24 +41,14 @@ SCALAR_TYPE@25..33: qubit[2] DESIGNATOR@30..33: [2] LITERAL@31..32: 2 NAME@34..36: q1 -OLD_STYLE_DECLARATION_STATEMENT@38..48: qreg q2[5] -INDEXED_IDENTIFIER@43..48: q2[5] +OLD_TYPED_PARAM@38..48: qreg q2[5] INDEX_OPERATOR@45..48: [5] EXPRESSION_LIST@46..47: 5 LITERAL@46..47: 5 -ERROR@48..49: ) -EXPR_STMT@50..52: -> -PREFIX_EXPR@50..52: -> -ERROR@51..52: > +RETURN_SIGNATURE@50..60: -> int[10] SCALAR_TYPE@53..60: int[10] DESIGNATOR@56..60: [10] LITERAL@57..59: 10 -NAME@61..61: -EXPR_STMT@61..137: { - int[10] result; - if (result == 2) return 1 + result; - return result; -} BLOCK_EXPR@61..137: { int[10] result; if (result == 2) return 1 + result; @@ -77,9 +71,13 @@ IDENTIFIER@111..117: result EXPR_STMT@121..135: return result; RETURN_EXPR@121..134: return result IDENTIFIER@128..134: result -DEF@138..171: def test_sub2(int[5] i, bit[2] b, +DEF@138..237: def test_sub2(int[5] i, bit[2] b, creg c[3]) { + for int[5] j in {2, 3} + i += j; + return i+1; +} NAME@142..151: test_sub2 -TYPED_PARAM_LIST@151..171: (int[5] i, bit[2] b, +TYPED_PARAM_LIST@151..182: (int[5] i, bit[2] b, creg c[3]) TYPED_PARAM@152..160: int[5] i SCALAR_TYPE@152..158: int[5] DESIGNATOR@155..158: [5] @@ -90,17 +88,10 @@ SCALAR_TYPE@162..168: bit[2] DESIGNATOR@165..168: [2] LITERAL@166..167: 2 NAME@169..170: b -OLD_STYLE_DECLARATION_STATEMENT@172..181: creg c[3] -INDEXED_IDENTIFIER@177..181: c[3] +OLD_TYPED_PARAM@172..181: creg c[3] INDEX_OPERATOR@178..181: [3] EXPRESSION_LIST@179..180: 3 LITERAL@179..180: 3 -ERROR@181..182: ) -EXPR_STMT@183..237: { - for int[5] j in {2, 3} - i += j; - return i+1; -} BLOCK_EXPR@183..237: { for int[5] j in {2, 3} i += j; diff --git a/crates/pipeline-tests/tests/snippets/reference/subroutine/subroutine.qasm b/crates/pipeline-tests/tests/snippets/reference/subroutine/subroutine.qasm index 1486c55..3d63a3c 100644 --- a/crates/pipeline-tests/tests/snippets/reference/subroutine/subroutine.qasm +++ b/crates/pipeline-tests/tests/snippets/reference/subroutine/subroutine.qasm @@ -1,5 +1,5 @@ // lex: ok -// parse: todo +// parse: ok // sema: skip def test_sub1(int[5] i, qubit[2] q1, qreg q2[5]) -> int[10] {