cqlib_core/compile/knowledge/rule_dsl/
parser.rs1use crate::circuit::Parameter;
21use crate::compile::knowledge::rule::Condition;
22use crate::compile::knowledge::rule_dsl::ast::{GatePattern, GateSpec, RuleDef};
23use crate::compile::knowledge::rule_dsl::lexer::{Lexer, Token, TokenKind};
24
25#[derive(Debug, Clone, PartialEq, thiserror::Error)]
27pub enum ParseError {
28 #[error("lexer error at byte {pos}: {msg}")]
30 Lexer {
31 msg: String,
33 pos: usize,
35 },
36 #[error("unexpected token at byte {pos}: expected {expected}, found {found}")]
38 UnexpectedToken {
39 expected: String,
41 found: String,
43 pos: usize,
45 },
46 #[error("empty expression at byte {pos}")]
48 EmptyExpr {
49 pos: usize,
51 },
52 #[error("invalid expression {expr:?}: {reason}")]
54 InvalidExpr {
55 expr: String,
57 reason: String,
59 },
60 #[error("invalid multi-controlled gate name at byte {pos}: {gate_name:?}")]
62 InvalidMultiControlledGateName {
63 gate_name: String,
65 pos: usize,
67 },
68}
69
70pub struct Parser<'a> {
72 input: &'a str,
74 lexer: Lexer<'a>,
76 current: Token<'a>,
78}
79
80impl<'a> Parser<'a> {
81 pub fn new(input: &'a str) -> Result<Self, ParseError> {
85 let mut lexer = Lexer::new(input);
86 let current = lexer.next_token().map_err(|e| ParseError::Lexer {
87 msg: e.msg,
88 pos: e.pos,
89 })?;
90 Ok(Self {
91 input,
92 lexer,
93 current,
94 })
95 }
96
97 fn advance(&mut self) -> Result<(), ParseError> {
99 self.current = self.lexer.next_token().map_err(|e| ParseError::Lexer {
100 msg: e.msg,
101 pos: e.pos,
102 })?;
103 Ok(())
104 }
105
106 fn expect(&mut self, kind: TokenKind) -> Result<Token<'a>, ParseError> {
109 if self.current.kind == kind {
110 let token = Token {
111 kind: self.current.kind.clone(),
112 text: self.current.text,
113 pos: self.current.pos,
114 };
115 self.advance()?;
116 Ok(token)
117 } else {
118 Err(ParseError::UnexpectedToken {
119 expected: format!("{:?}", kind),
120 found: format!("{:?}({})", self.current.kind, self.current.text),
121 pos: self.current.pos,
122 })
123 }
124 }
125
126 fn skip_newlines(&mut self) -> Result<(), ParseError> {
128 while self.current.kind == TokenKind::Newline {
129 self.advance()?;
130 }
131 Ok(())
132 }
133
134 pub fn parse_rule_file(&mut self) -> Result<Vec<RuleDef>, ParseError> {
136 let mut rules = Vec::new();
137 self.skip_newlines()?;
138 while self.current.kind != TokenKind::Eof {
139 rules.push(self.parse_rule()?);
140 self.skip_newlines()?;
141 }
142 Ok(rules)
143 }
144
145 fn parse_rule(&mut self) -> Result<RuleDef, ParseError> {
147 self.expect(TokenKind::Rule)?;
148 let name = self.expect(TokenKind::Ident)?.text.to_string();
149 self.expect(TokenKind::LBrace)?;
150 self.skip_newlines()?;
151
152 self.expect(TokenKind::Match)?;
153 self.expect(TokenKind::LBrace)?;
154 let match_ops = self.parse_gate_patterns()?;
155 self.expect(TokenKind::RBrace)?;
156 self.skip_newlines()?;
157
158 let mut conditions = Vec::new();
159 if self.current.kind == TokenKind::Require {
160 self.advance()?;
161 self.expect(TokenKind::LBrace)?;
162 conditions = self.parse_conditions()?;
163 self.expect(TokenKind::RBrace)?;
164 self.skip_newlines()?;
165 }
166
167 self.expect(TokenKind::Rewrite)?;
168 self.expect(TokenKind::LBrace)?;
169 let rewrite_ops = self.parse_gate_patterns()?;
170 self.expect(TokenKind::RBrace)?;
171 self.skip_newlines()?;
172
173 self.expect(TokenKind::RBrace)?;
174
175 Ok(RuleDef {
176 name,
177 match_ops,
178 conditions,
179 rewrite_ops,
180 })
181 }
182
183 fn parse_gate_patterns(&mut self) -> Result<Vec<GatePattern>, ParseError> {
189 let mut patterns = Vec::new();
190 self.skip_newlines()?;
191 while self.current.kind != TokenKind::RBrace && self.current.kind != TokenKind::Eof {
192 patterns.push(self.parse_gate_pattern()?);
193 match self.current.kind {
194 TokenKind::Comma => {
195 self.advance()?;
196 self.skip_newlines()?;
197 }
198 TokenKind::Newline => {
199 self.skip_newlines()?;
200 }
201 TokenKind::RBrace | TokenKind::Eof => {}
202 _ => {
203 return Err(ParseError::UnexpectedToken {
204 expected: "Comma, Newline, or RBrace".to_string(),
205 found: format!("{:?}({})", self.current.kind, self.current.text),
206 pos: self.current.pos,
207 });
208 }
209 }
210 }
211 Ok(patterns)
212 }
213
214 fn parse_gate_pattern(&mut self) -> Result<GatePattern, ParseError> {
216 let gate_token = self.expect(TokenKind::Ident)?;
217 let gate_name = gate_token.text.to_string();
218 let gate = if self.current.kind == TokenKind::LBracket {
219 self.advance()?;
220 let control_token = self.expect(TokenKind::Number)?;
221 let added_controls =
222 control_token
223 .text
224 .parse::<u8>()
225 .map_err(|_| ParseError::UnexpectedToken {
226 expected: "u8 multi-control count".to_string(),
227 found: control_token.text.to_string(),
228 pos: control_token.pos,
229 })?;
230 self.expect(TokenKind::RBracket)?;
231 let base_gate_name = gate_name.strip_prefix("MC").ok_or_else(|| {
232 ParseError::InvalidMultiControlledGateName {
233 gate_name: gate_name.clone(),
234 pos: gate_token.pos,
235 }
236 })?;
237 if base_gate_name.is_empty() {
238 return Err(ParseError::InvalidMultiControlledGateName {
239 gate_name,
240 pos: gate_token.pos,
241 });
242 }
243 GateSpec::MultiControlled {
244 base_gate_name: base_gate_name.to_string(),
245 added_controls,
246 }
247 } else {
248 GateSpec::Standard { gate_name }
249 };
250
251 let mut params = Vec::new();
252 if self.current.kind == TokenKind::LParen {
253 self.advance()?;
254 if self.current.kind != TokenKind::RParen {
255 params.push(self.parse_param()?);
256 while self.current.kind == TokenKind::Comma {
257 self.advance()?;
258 params.push(self.parse_param()?);
259 }
260 }
261 self.expect(TokenKind::RParen)?;
262 }
263
264 let mut qubits = Vec::new();
265 while self.current.kind == TokenKind::Number {
266 let text = self.current.text;
267 let q = text
268 .parse::<u32>()
269 .map_err(|_| ParseError::UnexpectedToken {
270 expected: "qubit index".to_string(),
271 found: text.to_string(),
272 pos: self.current.pos,
273 })?;
274 qubits.push(q);
275 self.advance()?;
276 }
277
278 Ok(GatePattern {
279 gate,
280 params,
281 qubits,
282 })
283 }
284
285 fn parse_param(&mut self) -> Result<Parameter, ParseError> {
287 self.parse_expr(|kind| *kind == TokenKind::Comma || *kind == TokenKind::RParen)
288 }
289
290 fn parse_conditions(&mut self) -> Result<Vec<Condition>, ParseError> {
296 let mut conditions = Vec::new();
297 self.skip_newlines()?;
298 while self.current.kind != TokenKind::RBrace && self.current.kind != TokenKind::Eof {
299 conditions.push(self.parse_condition()?);
300 match self.current.kind {
301 TokenKind::Comma => {
302 self.advance()?;
303 self.skip_newlines()?;
304 }
305 TokenKind::Newline => {
306 self.skip_newlines()?;
307 }
308 TokenKind::RBrace | TokenKind::Eof => {}
309 _ => {
310 return Err(ParseError::UnexpectedToken {
311 expected: "Comma, Newline, or RBrace".to_string(),
312 found: format!("{:?}({})", self.current.kind, self.current.text),
313 pos: self.current.pos,
314 });
315 }
316 }
317 }
318 Ok(conditions)
319 }
320
321 fn parse_condition(&mut self) -> Result<Condition, ParseError> {
323 let lhs = self.parse_expr(|kind| *kind == TokenKind::EqEq)?;
324 self.expect(TokenKind::EqEq)?;
325 let rhs = self.parse_expr(|kind| {
326 *kind == TokenKind::Mod
327 || *kind == TokenKind::Comma
328 || *kind == TokenKind::Newline
329 || *kind == TokenKind::RBrace
330 })?;
331
332 if self.current.kind == TokenKind::Mod {
333 self.advance()?;
334 let modulus = self.parse_expr(|kind| {
335 *kind == TokenKind::Comma
336 || *kind == TokenKind::Newline
337 || *kind == TokenKind::RBrace
338 })?;
339 Ok(Condition::EqMod(lhs, rhs, modulus))
340 } else {
341 Ok(Condition::Eq(lhs, rhs))
342 }
343 }
344
345 fn parse_expr(&mut self, stop: impl Fn(&TokenKind) -> bool) -> Result<Parameter, ParseError> {
351 let start = self.current.pos;
352 let mut paren_depth = 0usize;
353 while self.current.kind != TokenKind::Eof {
354 if paren_depth == 0 && stop(&self.current.kind) {
355 break;
356 }
357 match self.current.kind {
358 TokenKind::LParen => paren_depth += 1,
359 TokenKind::RParen if paren_depth > 0 => paren_depth -= 1,
360 _ => {}
361 }
362 self.advance()?;
363 }
364 let end = self.current.pos;
365 let expr_str = self.input[start..end].trim();
366 if expr_str.is_empty() {
367 return Err(ParseError::EmptyExpr { pos: start });
368 }
369 Parameter::try_from(expr_str).map_err(|e| ParseError::InvalidExpr {
370 expr: expr_str.to_string(),
371 reason: format!("{}", e),
372 })
373 }
374}
375
376#[cfg(test)]
377mod tests {
378 use super::*;
379 use crate::circuit::ParameterValue;
380
381 #[test]
382 fn parse_cancel_rule() {
383 let input = r#"
384 rule cancel_rx_inverse {
385 match {
386 RX(a) 0
387 RX(b) 0
388 }
389 require {
390 a + b == 0 mod 2*π
391 }
392 rewrite {
393 }
394 }
395
396 rule cancel_h {
397 match {
398 H 0
399 H 0
400 }
401 rewrite {
402 }
403 }
404 "#;
405 let mut parser = Parser::new(input).unwrap();
406 let rules = parser.parse_rule_file().unwrap();
407 assert_eq!(rules.len(), 2);
408
409 let r0 = rules[0].clone().into_rule().unwrap();
411 assert_eq!(r0.name, "cancel_rx_inverse");
412 assert_eq!(r0.operations.len(), 2);
413 assert_eq!(r0.conditions.as_ref().unwrap().len(), 1);
414 assert!(r0.target.is_empty());
415
416 let r1 = rules[1].clone().into_rule().unwrap();
418 assert_eq!(r1.name, "cancel_h");
419 assert_eq!(r1.operations.len(), 2);
420 assert!(r1.conditions.is_none());
421 assert!(r1.target.is_empty());
422 }
423
424 #[test]
425 fn parse_merge_rule() {
426 let input = r#"
427 rule merge_rz {
428 match {
429 RZ(a) 0
430 RZ(b) 0
431 }
432 rewrite {
433 RZ(a + b) 0
434 }
435 }
436 "#;
437 let mut parser = Parser::new(input).unwrap();
438 let rules = parser.parse_rule_file().unwrap();
439 assert_eq!(rules.len(), 1);
440
441 let r = rules[0].clone().into_rule().unwrap();
442 assert_eq!(r.name, "merge_rz");
443 assert_eq!(r.operations.len(), 2);
444 assert_eq!(r.target.len(), 1);
445
446 let target = &r.target[0];
447 assert_eq!(target.qubits.as_slice(), &[0]);
448 let params = target.params.as_ref().unwrap();
449 assert_eq!(params.len(), 1);
450 match ¶ms[0] {
451 ParameterValue::Param(p) => {
452 assert_eq!(p.to_string(), "a + b");
453 }
454 _ => panic!("expected Expr pattern"),
455 }
456 }
457
458 #[test]
459 fn parse_newline_separated_patterns() {
460 let input = r#"rule test {
461 match { H 0
462 H 0
463 H 0 }
464 rewrite {}
465 }"#;
466 let mut parser = Parser::new(input).unwrap();
467 let rules = parser.parse_rule_file().unwrap();
468 let r = rules[0].clone().into_rule().unwrap();
469 assert_eq!(r.operations.len(), 3);
470 }
471
472 #[test]
473 fn parse_comma_separated_patterns() {
474 let input = r#"rule test {
475 match { H 0, H 0, H 0 }
476 rewrite {}
477 }"#;
478 let mut parser = Parser::new(input).unwrap();
479 let rules = parser.parse_rule_file().unwrap();
480 let r = rules[0].clone().into_rule().unwrap();
481 assert_eq!(r.operations.len(), 3);
482 }
483
484 #[test]
485 fn reject_same_line_patterns_without_comma() {
486 let input = r#"rule test {
487 match { H 0 H 0 }
488 rewrite {}
489 }"#;
490 let mut parser = Parser::new(input).unwrap();
491 assert!(parser.parse_rule_file().is_err());
492 }
493
494 #[test]
495 fn parse_nested_parenthesized_param_expr() {
496 let input = r#"rule test {
497 match { RZ(a) 0 }
498 rewrite { RZ((a + 1)) 0 }
499 }"#;
500 let mut parser = Parser::new(input).unwrap();
501 let rules = parser.parse_rule_file().unwrap();
502 let r = rules[0].clone().into_rule().unwrap();
503 assert_eq!(r.target.len(), 1);
504 }
505
506 #[test]
507 fn parse_gphase_rule() {
508 let input = r#"
509 rule merge_gphase {
510 match { GPhase(a), GPhase(b) }
511 rewrite { GPhase(a + b) }
512 }
513 rule cancel_gphase_inverse {
514 match { GPhase(a), GPhase(b) }
515 require { a + b == 0 mod 2*π }
516 rewrite {}
517 }
518 "#;
519 let mut parser = Parser::new(input).unwrap();
520 let rules = parser.parse_rule_file().unwrap();
521 assert_eq!(rules.len(), 2);
522
523 let r0 = rules[0].clone().into_rule().unwrap();
524 assert_eq!(r0.name, "merge_gphase");
525 assert_eq!(r0.operations.len(), 2);
526 assert!(r0.operations[0].qubits.is_empty());
527 assert_eq!(r0.target.len(), 1);
528 assert!(r0.target[0].qubits.is_empty());
529
530 let r1 = rules[1].clone().into_rule().unwrap();
531 assert_eq!(r1.name, "cancel_gphase_inverse");
532 assert_eq!(r1.operations.len(), 2);
533 assert!(r1.operations[0].qubits.is_empty());
534 assert_eq!(r1.conditions.as_ref().unwrap().len(), 1);
535 assert!(r1.target.is_empty());
536 }
537
538 #[test]
539 fn parse_multi_controlled_gate_pattern() {
540 let input = r#"rule decompose_m3cx {
541 match { MCX[3] 0 1 2 3 }
542 rewrite { CCX 0 1 2 }
543 }"#;
544 let mut parser = Parser::new(input).unwrap();
545 let rules = parser.parse_rule_file().unwrap();
546 assert_eq!(rules.len(), 1);
547 let pattern = &rules[0].match_ops[0];
548 assert_eq!(
549 pattern.gate,
550 GateSpec::MultiControlled {
551 base_gate_name: "X".to_string(),
552 added_controls: 3
553 }
554 );
555 assert_eq!(pattern.qubits, vec![0, 1, 2, 3]);
556 }
557
558 #[test]
559 fn parse_parameterized_multi_controlled_gate_pattern() {
560 let input = r#"rule decompose_m2rz {
561 match { MCRZ[2](theta) 0 1 2 }
562 rewrite { CRZ(theta) 1 2 }
563 }"#;
564 let mut parser = Parser::new(input).unwrap();
565 let rules = parser.parse_rule_file().unwrap();
566 assert_eq!(rules[0].match_ops[0].params.len(), 1);
567 assert_eq!(
568 rules[0].match_ops[0].gate,
569 GateSpec::MultiControlled {
570 base_gate_name: "RZ".to_string(),
571 added_controls: 2
572 }
573 );
574 }
575
576 #[test]
577 fn reject_bracketed_non_multi_controlled_gate_name() {
578 let input = r#"rule bad {
579 match { X[3] 0 1 2 3 }
580 rewrite {}
581 }"#;
582 let mut parser = Parser::new(input).unwrap();
583 assert!(matches!(
584 parser.parse_rule_file(),
585 Err(ParseError::InvalidMultiControlledGateName { .. })
586 ));
587 }
588
589 #[test]
590 fn reject_fractional_multi_control_count() {
591 let input = r#"rule bad {
592 match { MCX[1.5] 0 1 }
593 rewrite {}
594 }"#;
595 let mut parser = Parser::new(input).unwrap();
596 assert!(matches!(
597 parser.parse_rule_file(),
598 Err(ParseError::UnexpectedToken { .. })
599 ));
600 }
601}