diff --git a/crates/oq3_parser/src/grammar.rs b/crates/oq3_parser/src/grammar.rs index 0dd5f1f..93f6081 100644 --- a/crates/oq3_parser/src/grammar.rs +++ b/crates/oq3_parser/src/grammar.rs @@ -94,12 +94,13 @@ impl BlockLike { } } -fn scalar_type(p: &mut Parser<'_>) { - assert!(p.current().is_scalar_type()); - let r = p.start(); - p.bump_any(); - r.complete(p, SCALAR_TYPE); -} +// FIXME: was only used in opt_ret_type. But no longer even there +// fn scalar_type(p: &mut Parser<'_>) { +// assert!(p.current().is_scalar_type()); +// let r = p.start(); +// p.bump_any(); +// r.complete(p, SCALAR_TYPE); +// } /// Parse the optional return signature of a `defcal` or `def` definition. /// Return `true` if the return type was found, else `false. @@ -107,10 +108,13 @@ fn opt_ret_type(p: &mut Parser<'_>) -> bool { if p.at(T![->]) { let m = p.start(); p.bump(T![->]); + if !p.current().is_scalar_type() { + p.error("Expected scalar return type after ->"); + } + // Allow any type, with possible error. if p.current().is_type() { - scalar_type(p); + expressions::type_spec(p); } else { - p.error("Expected return type after ->"); m.abandon(p); return false; } diff --git a/crates/oq3_parser/src/grammar/expressions.rs b/crates/oq3_parser/src/grammar/expressions.rs index 0fe2ae1..f1fa36e 100644 --- a/crates/oq3_parser/src/grammar/expressions.rs +++ b/crates/oq3_parser/src/grammar/expressions.rs @@ -363,6 +363,10 @@ fn call_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { fn type_name(p: &mut Parser<'_>) { if !p.current().is_type() { p.error("Expected type name."); + // Return without parsing whatever is here. + // Probably an identifier because the entire type spec is missing. + // If we eat it now. We will get another (false) error for a missing parameter. + return; } p.bump(p.current()); } @@ -454,7 +458,12 @@ pub(crate) fn designator(p: &mut Parser<'_>) -> bool { pub(crate) fn var_name(p: &mut Parser<'_>) { let m = p.start(); - p.expect(IDENT); // The declared identifier, ie variable name + if p.at(IDENT) { + // The declared identifier, ie variable name + p.bump_any(); + } else { + p.error("Expecting parameter name."); + } m.complete(p, NAME); } diff --git a/crates/oq3_parser/src/grammar/items.rs b/crates/oq3_parser/src/grammar/items.rs index e2ddec9..3de930c 100644 --- a/crates/oq3_parser/src/grammar/items.rs +++ b/crates/oq3_parser/src/grammar/items.rs @@ -89,7 +89,7 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker) -> Result<(), Marker> { T![if] => if_stmt(p, m), T![while] => while_stmt(p, m), T![for] => for_stmt(p, m), - T![def] => def_(p, m), + T![def] => def_stmt(p, m), T![defcal] => defcal_(p, m), T![cal] => cal_(p, m), T![defcalgrammar] => defcalgrammar_(p, m), @@ -336,8 +336,9 @@ fn io_declaration_stmt(p: &mut Parser<'_>, m: Marker) { m.complete(p, I_O_DECLARATION_STATEMENT); } -fn def_(p: &mut Parser<'_>, m: Marker) { - p.bump(T![def]); +fn def_stmt(p: &mut Parser<'_>, m: Marker) { + assert!(p.at(T![def])); + p.bump_any(); // Read the name of the subroutine. (This records an error message on failure.) name_r(p, ITEM_RECOVERY_SET); diff --git a/crates/oq3_parser/src/grammar/params.rs b/crates/oq3_parser/src/grammar/params.rs index 6ffe5e6..8ac9223 100644 --- a/crates/oq3_parser/src/grammar/params.rs +++ b/crates/oq3_parser/src/grammar/params.rs @@ -133,6 +133,7 @@ fn _param_list_openqasm(p: &mut Parser<'_>, flavor: DefFlavor, m: Option DefCalQubits => QUBIT_LIST, GateCallQubits => QUBIT_LIST, ExpressionList => EXPRESSION_LIST, + DefParams | DefCalParams => TYPED_PARAM_LIST, _ => PARAM_LIST, }; list_marker.complete(p, kind); @@ -181,21 +182,10 @@ fn param_untyped(p: &mut Parser<'_>, m: Marker) -> bool { } fn param_typed(p: &mut Parser<'_>, m: Marker) -> bool { - let mut success = true; - if p.current().is_type() { - p.bump_any(); - } else { - p.error("expected type annotation"); - success = false; - } - if !p.at(IDENT) { - p.error("expected parameter name"); - m.abandon(p); - return false; - } - p.bump(IDENT); - m.complete(p, PARAM); - success + expressions::type_spec(p); + expressions::var_name(p); + m.complete(p, TYPED_PARAM); + true } // These can be cast to GateOperand 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 b3da507..56c0e87 100644 --- a/crates/oq3_parser/src/syntax_kind/syntax_kind_enum.rs +++ b/crates/oq3_parser/src/syntax_kind/syntax_kind_enum.rs @@ -179,9 +179,11 @@ pub enum SyntaxKind { EXPR_STMT, TYPE, PARAM_LIST, + TYPED_PARAM_LIST, QUBIT_LIST, FILE_PATH, PARAM, + TYPED_PARAM, ARG_LIST, VERSION, VERSION_STRING, diff --git a/crates/oq3_semantics/src/asg.rs b/crates/oq3_semantics/src/asg.rs index 591e3f0..07b07f3 100644 --- a/crates/oq3_semantics/src/asg.rs +++ b/crates/oq3_semantics/src/asg.rs @@ -177,7 +177,7 @@ pub enum Stmt { DeclareClassical(Box), DeclareQuantum(DeclareQuantum), DeclareHardwareQubit(DeclareHardwareQubit), - Def, // stub + DefStmt(DefStmt), DefCal, // stub Delay(DelayStmt), End, @@ -602,6 +602,50 @@ impl GateDeclaration { } } +#[derive(Clone, Debug, PartialEq)] +pub struct DefStmt { + name: SymbolIdResult, + params: Vec, + block: Block, + return_type: Option, +} + +impl DefStmt { + pub fn new( + name: SymbolIdResult, + params: Vec, + block: Block, + return_type: Option, + ) -> DefStmt { + DefStmt { + name, + params, + block, + return_type, + } + } + + pub fn to_stmt(self) -> Stmt { + Stmt::DefStmt(self) + } + + pub fn name(&self) -> &SymbolIdResult { + &self.name + } + + pub fn params(&self) -> &[SymbolIdResult] { + self.params.as_ref() + } + + pub fn block(&self) -> &Block { + &self.block + } + + pub fn return_type(&self) -> Option<&Type> { + self.return_type.as_ref() + } +} + #[derive(Clone, Debug, PartialEq)] pub struct MeasureExpression { operand: TExpr, diff --git a/crates/oq3_semantics/src/syntax_to_semantics.rs b/crates/oq3_semantics/src/syntax_to_semantics.rs index 3ca50b8..a75ff06 100644 --- a/crates/oq3_semantics/src/syntax_to_semantics.rs +++ b/crates/oq3_semantics/src/syntax_to_semantics.rs @@ -339,9 +339,9 @@ fn from_stmt(stmt: synast::Stmt, context: &mut Context) -> Option { // 1. a sequnce of semicolon-separated stmts. // or 2. a single block. But the block has a scope of course. with_scope!(context, ScopeType::Subroutine, - let params = bind_parameter_list(gate.angle_params(), &Type::Angle(None, IsConst::True), context); - let qubits = bind_parameter_list(gate.qubit_params(), &Type::Qubit, context).unwrap(); - let block = from_block_expr(gate.body().unwrap(), context); + let params = bind_parameter_list(gate.angle_params(), &Type::Angle(None, IsConst::True), context); + let qubits = bind_parameter_list(gate.qubit_params(), &Type::Qubit, context).unwrap(); + let block = from_block_expr(gate.body().unwrap(), context); ); let num_params = match params { Some(ref params) => params.len(), @@ -355,10 +355,33 @@ fn from_stmt(stmt: synast::Stmt, context: &mut Context) -> Option { ), &name_node, ); - Some(asg::GateDeclaration::new(gate_name_symbol_id, params, qubits, block).to_stmt()) } + synast::Stmt::Def(def_stmt) => { + let name_node = def_stmt.name().unwrap(); + with_scope!(context, ScopeType::Subroutine, + let params = bind_typed_parameter_list(def_stmt.typed_param_list(), context); + let block = from_block_expr(def_stmt.body().unwrap(), context); + ); + // FIXME: Should we let subroutines have a parameterized type? + // This would be very convenient for matching signatures. + // let num_params = match params { + // Some(ref params) => params.len(), + // None => 0, + // }; + let ret_type = def_stmt.return_signature() + .and_then(|x| x.scalar_type()) + .map(|x| from_scalar_type(&x, true, context)); + + let def_name_symbol_id = context.new_binding( + name_node.string().as_ref(), + &Type::Void, + &name_node, + ); + Some(asg::DefStmt::new(def_name_symbol_id, params.unwrap(), block, ret_type).to_stmt()) + } + synast::Stmt::Barrier(barrier) => { let gate_operands = barrier.qubit_list().map(|operands| { operands @@ -433,7 +456,6 @@ fn from_stmt(stmt: synast::Stmt, context: &mut Context) -> Option { } synast::Stmt::Cal(_) - | synast::Stmt::Def(_) | synast::Stmt::DefCal(_) | synast::Stmt::DefCalGrammar(_) // The following two should probably be removed from the syntax parser. @@ -909,6 +931,7 @@ fn from_scalar_type( synast::ScalarTypeKind::None => panic!("You have found a bug in oq3_parser"), synast::ScalarTypeKind::Stretch => Type::Stretch(isconst.into()), synast::ScalarTypeKind::UInt => Type::UInt(width, isconst.into()), + synast::ScalarTypeKind::Qubit => Type::Qubit, } } @@ -1039,6 +1062,22 @@ fn bind_parameter_list( }) } +fn bind_typed_parameter_list( + inparam_list: Option, + context: &mut Context, +) -> Option> { + inparam_list.map(|param_list| { + param_list + .typed_params() + .map(|param| { + let typ = from_scalar_type(¶m.scalar_type().unwrap(), false, context); + let namestr = param.name().unwrap().string(); + context.new_binding(namestr.as_ref(), &typ, ¶m) + }) + .collect() + }) +} + // This works, but using it is pretty clumsy. // fn with_scope(context: &mut Context, scope: ScopeType, func: F) where // F: FnOnce(&mut Context) diff --git a/crates/oq3_semantics/src/types.rs b/crates/oq3_semantics/src/types.rs index d6fb0e8..4a4aba5 100644 --- a/crates/oq3_semantics/src/types.rs +++ b/crates/oq3_semantics/src/types.rs @@ -72,14 +72,13 @@ pub enum Type { // Other Gate(i32, i32), // (num classical args, num quantum args) - Range, // temporary placeholder, perhaps + Range, Set, Void, ToDo, // not yet implemented // Undefined means a type that is erroneously non-existent. This is not the same as unknown. // The prototypical application is trying to resolve an unbound identifier. Undefined, - // Void, do we need this? } // OQ3 supports arrays with number of dims up to seven. diff --git a/crates/oq3_semantics/tests/from_string_tests.rs b/crates/oq3_semantics/tests/from_string_tests.rs index 027e0ce..980d195 100644 --- a/crates/oq3_semantics/tests/from_string_tests.rs +++ b/crates/oq3_semantics/tests/from_string_tests.rs @@ -619,3 +619,48 @@ delay[x] q; assert_eq!(errors.len(), 1); assert_eq!(program.len(), 3); } + +#[test] +fn test_from_string_def_1() { + let code = r##" +gate h q {} +def xmeasure(qubit q) -> bit { h q; return measure q; } +"##; + let (program, errors, _symbol_table) = parse_string(code); + assert_eq!(errors.len(), 0); + assert_eq!(program.len(), 2); +} + +#[test] +fn test_from_string_def_2() { + let code = r##" +gate h q {} +gate rz(theta) q {} + +def pmeasure(angle[32] theta, qubit q) -> bit { + rz(theta) q; + h q; + return measure q; +} +"##; + let (program, errors, _symbol_table) = parse_string(code); + assert_eq!(errors.len(), 0); + assert_eq!(program.len(), 3); +} + +// Issue #183 +#[test] +fn test_from_string_def_3() { + let code = r##" +gate cx p, q {} + +def xcheck(qubit[4] d, qubit a) -> bit { + reset a; + for int i in [0: 3] {cx d[i], a;} + return measure a; +} +"##; + let (program, errors, _symbol_table) = parse_string(code); + assert_eq!(errors.len(), 1); + assert_eq!(program.len(), 2); +} diff --git a/crates/oq3_syntax/examples/itemparse.rs b/crates/oq3_syntax/examples/itemparse.rs index e192fbe..26bacc8 100644 --- a/crates/oq3_syntax/examples/itemparse.rs +++ b/crates/oq3_syntax/examples/itemparse.rs @@ -160,8 +160,8 @@ fn print_defcal(defcal: ast::DefCal) { fn print_def(def: ast::Def) { println!("Def\ndef name: '{}'", def.name().unwrap()); - if def.param_list().is_some() { - println!("parameters: '{}'", def.param_list().unwrap()); + if def.typed_param_list().is_some() { + println!("parameters: '{}'", def.typed_param_list().unwrap()); } if def.return_signature().is_some() { println!("return type: '{}'", def.return_signature().unwrap()); diff --git a/crates/oq3_syntax/openqasm3.ungram b/crates/oq3_syntax/openqasm3.ungram index 2857292..b8526ec 100644 --- a/crates/oq3_syntax/openqasm3.ungram +++ b/crates/oq3_syntax/openqasm3.ungram @@ -154,7 +154,7 @@ FilePath = // Subroutine definition Def = - 'def' Name ParamList ReturnSignature? + 'def' Name TypedParamList ReturnSignature? (body:BlockExpr | ';') // Defcal definition @@ -179,6 +179,12 @@ Gate = ParamList = '(' (Param (',' Param)* ','?)? ')' +TypedParamList = + '(' (TypedParam (',' TypedParam)* ','?)? ')' + +TypedParam = + ScalarType Name + // List with no delimeters QubitList = (GateOperand (',' GateOperand)* ','?)? diff --git a/crates/oq3_syntax/src/ast/generated/nodes.rs b/crates/oq3_syntax/src/ast/generated/nodes.rs index 5cf7277..0da20cb 100644 --- a/crates/oq3_syntax/src/ast/generated/nodes.rs +++ b/crates/oq3_syntax/src/ast/generated/nodes.rs @@ -152,7 +152,7 @@ impl Def { pub fn def_token(&self) -> Option { support::token(&self.syntax, T![def]) } - pub fn param_list(&self) -> Option { + pub fn typed_param_list(&self) -> Option { support::child(&self.syntax) } pub fn return_signature(&self) -> Option { @@ -559,14 +559,14 @@ pub struct FilePath { } impl FilePath {} #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ParamList { +pub struct TypedParamList { pub(crate) syntax: SyntaxNode, } -impl ParamList { +impl TypedParamList { pub fn l_paren_token(&self) -> Option { support::token(&self.syntax, T!['(']) } - pub fn params(&self) -> AstChildren { + pub fn typed_params(&self) -> AstChildren { support::children(&self.syntax) } pub fn r_paren_token(&self) -> Option { @@ -586,12 +586,82 @@ impl ReturnSignature { } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ParamList { + pub(crate) syntax: SyntaxNode, +} +impl ParamList { + pub fn l_paren_token(&self) -> Option { + support::token(&self.syntax, T!['(']) + } + pub fn params(&self) -> AstChildren { + support::children(&self.syntax) + } + pub fn r_paren_token(&self) -> Option { + support::token(&self.syntax, T![')']) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Param { pub(crate) syntax: SyntaxNode, } impl ast::HasName for Param {} impl Param {} #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TypedParam { + pub(crate) syntax: SyntaxNode, +} +impl ast::HasName for TypedParam {} +impl TypedParam { + pub fn scalar_type(&self) -> Option { + support::child(&self.syntax) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ScalarType { + pub(crate) syntax: SyntaxNode, +} +impl ScalarType { + pub fn bit_token(&self) -> Option { + support::token(&self.syntax, T![bit]) + } + pub fn designator(&self) -> Option { + support::child(&self.syntax) + } + pub fn int_token(&self) -> Option { + support::token(&self.syntax, T![int]) + } + pub fn uint_token(&self) -> Option { + support::token(&self.syntax, T![uint]) + } + pub fn float_token(&self) -> Option { + support::token(&self.syntax, T![float]) + } + pub fn angle_token(&self) -> Option { + support::token(&self.syntax, T![angle]) + } + pub fn bool_token(&self) -> Option { + support::token(&self.syntax, T![bool]) + } + pub fn duration_token(&self) -> Option { + support::token(&self.syntax, T![duration]) + } + pub fn stretch_token(&self) -> Option { + support::token(&self.syntax, T![stretch]) + } + pub fn complex_token(&self) -> Option { + support::token(&self.syntax, T![complex]) + } + pub fn l_brack_token(&self) -> Option { + support::token(&self.syntax, T!['[']) + } + pub fn scalar_type(&self) -> Option { + support::child(&self.syntax) + } + pub fn r_brack_token(&self) -> Option { + support::token(&self.syntax, T![']']) + } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ArrayExpr { pub(crate) syntax: SyntaxNode, } @@ -867,51 +937,6 @@ impl ArgList { } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ScalarType { - pub(crate) syntax: SyntaxNode, -} -impl ScalarType { - pub fn bit_token(&self) -> Option { - support::token(&self.syntax, T![bit]) - } - pub fn designator(&self) -> Option { - support::child(&self.syntax) - } - pub fn int_token(&self) -> Option { - support::token(&self.syntax, T![int]) - } - pub fn uint_token(&self) -> Option { - support::token(&self.syntax, T![uint]) - } - pub fn float_token(&self) -> Option { - support::token(&self.syntax, T![float]) - } - pub fn angle_token(&self) -> Option { - support::token(&self.syntax, T![angle]) - } - pub fn bool_token(&self) -> Option { - support::token(&self.syntax, T![bool]) - } - pub fn duration_token(&self) -> Option { - support::token(&self.syntax, T![duration]) - } - pub fn stretch_token(&self) -> Option { - support::token(&self.syntax, T![stretch]) - } - pub fn complex_token(&self) -> Option { - support::token(&self.syntax, T![complex]) - } - pub fn l_brack_token(&self) -> Option { - support::token(&self.syntax, T!['[']) - } - pub fn scalar_type(&self) -> Option { - support::child(&self.syntax) - } - pub fn r_brack_token(&self) -> Option { - support::token(&self.syntax, T![']']) - } -} -#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ArrayType { pub(crate) syntax: SyntaxNode, } @@ -1675,9 +1700,9 @@ impl AstNode for FilePath { &self.syntax } } -impl AstNode for ParamList { +impl AstNode for TypedParamList { fn can_cast(kind: SyntaxKind) -> bool { - kind == PARAM_LIST + kind == TYPED_PARAM_LIST } fn cast(syntax: SyntaxNode) -> Option { if Self::can_cast(syntax.kind()) { @@ -1705,6 +1730,21 @@ impl AstNode for ReturnSignature { &self.syntax } } +impl AstNode for ParamList { + fn can_cast(kind: SyntaxKind) -> bool { + kind == PARAM_LIST + } + 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 Param { fn can_cast(kind: SyntaxKind) -> bool { kind == PARAM @@ -1720,6 +1760,36 @@ impl AstNode for Param { &self.syntax } } +impl AstNode for TypedParam { + fn can_cast(kind: SyntaxKind) -> bool { + kind == 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 ScalarType { + fn can_cast(kind: SyntaxKind) -> bool { + kind == SCALAR_TYPE + } + 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 @@ -2050,21 +2120,6 @@ impl AstNode for ArgList { &self.syntax } } -impl AstNode for ScalarType { - fn can_cast(kind: SyntaxKind) -> bool { - kind == SCALAR_TYPE - } - 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 ArrayType { fn can_cast(kind: SyntaxKind) -> bool { kind == ARRAY_TYPE @@ -2778,6 +2833,7 @@ impl AstNode for AnyHasName { | LET_STMT | QUANTUM_DECLARATION_STATEMENT | PARAM + | TYPED_PARAM | GATE_CALL_EXPR | HARDWARE_QUBIT | INDEXED_IDENTIFIER @@ -2996,7 +3052,7 @@ impl std::fmt::Display for FilePath { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for ParamList { +impl std::fmt::Display for TypedParamList { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } @@ -3006,11 +3062,26 @@ impl std::fmt::Display for ReturnSignature { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for ParamList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for Param { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for TypedParam { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} +impl std::fmt::Display for ScalarType { + 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) @@ -3121,11 +3192,6 @@ impl std::fmt::Display for ArgList { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for ScalarType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self.syntax(), f) - } -} impl std::fmt::Display for ArrayType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/oq3_syntax/src/ast/type_ext.rs b/crates/oq3_syntax/src/ast/type_ext.rs index 6b23a77..4fe3703 100644 --- a/crates/oq3_syntax/src/ast/type_ext.rs +++ b/crates/oq3_syntax/src/ast/type_ext.rs @@ -3,6 +3,9 @@ use crate::{ast, SyntaxToken, T}; +// `ScalarTypeKind` includes Qubit because thus far, we only +// use it for def can defcall, which allows mixing scalar and qubits +// in a list of parameters. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum ScalarTypeKind { Angle, @@ -12,9 +15,10 @@ pub enum ScalarTypeKind { Duration, Float, Int, - None, // For testing. Remove this + None, // Use this to record errors Stretch, UInt, + Qubit, } impl ast::ScalarType { @@ -30,7 +34,8 @@ impl ast::ScalarType { T![int] => Int, T![stretch] => Stretch, T![uint] => UInt, - _ => None, // record an error ? + T![qubit] => Qubit, + _ => None, } } diff --git a/crates/oq3_syntax/src/tests/ast_src.rs b/crates/oq3_syntax/src/tests/ast_src.rs index a0cff04..75e944a 100644 --- a/crates/oq3_syntax/src/tests/ast_src.rs +++ b/crates/oq3_syntax/src/tests/ast_src.rs @@ -190,9 +190,11 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc { "EXPR_STMT", "TYPE", "PARAM_LIST", + "TYPED_PARAM_LIST", "QUBIT_LIST", "FILE_PATH", "PARAM", + "TYPED_PARAM", "ARG_LIST", "VERSION", "VERSION_STRING",