1use std::collections::HashSet;
18use std::error;
19use std::mem;
20use std::str::FromStr;
21use std::sync::LazyLock;
22
23use itertools::Itertools as _;
24use pest::Parser as _;
25use pest::iterators::Pair;
26use pest::pratt_parser::Assoc;
27use pest::pratt_parser::Op;
28use pest::pratt_parser::PrattParser;
29use thiserror::Error;
30
31use self::private::RevsetParser;
32use self::private::Rule;
33use crate::dsl_util;
34use crate::dsl_util::AliasDeclaration;
35use crate::dsl_util::AliasDeclarationParser;
36use crate::dsl_util::AliasDefinitionParser;
37use crate::dsl_util::AliasExpandError;
38use crate::dsl_util::AliasExpandableExpression;
39use crate::dsl_util::AliasId;
40use crate::dsl_util::AliasesMap;
41use crate::dsl_util::Diagnostics;
42use crate::dsl_util::ExpressionFolder;
43use crate::dsl_util::FoldableExpression;
44use crate::dsl_util::FunctionCallParser;
45use crate::dsl_util::InvalidArguments;
46use crate::dsl_util::StringLiteralParser;
47use crate::dsl_util::collect_similar;
48use crate::ref_name::RefNameBuf;
49use crate::ref_name::RemoteNameBuf;
50use crate::ref_name::RemoteRefSymbolBuf;
51use crate::symbol_util::format_string;
52
53mod private {
54 use pest_derive::Parser;
55
56 #[derive(Parser)]
58 #[grammar = "revset.pest"]
59 pub struct RevsetParser;
60}
61
62const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser {
63 content_rule: Rule::string_content,
64 escape_rule: Rule::string_escape,
65};
66const FUNCTION_CALL_PARSER: FunctionCallParser<Rule> = FunctionCallParser {
67 function_name_rule: Rule::function_name,
68 function_arguments_rule: Rule::function_arguments,
69 keyword_argument_rule: Rule::keyword_argument,
70 argument_name_rule: Rule::strict_identifier,
71 argument_value_rule: Rule::expression,
72};
73
74impl Rule {
75 fn is_compat(&self) -> bool {
78 matches!(
79 self,
80 Self::compat_parents_op
81 | Self::compat_dag_range_op
82 | Self::compat_dag_range_pre_op
83 | Self::compat_dag_range_post_op
84 | Self::compat_add_op
85 | Self::compat_sub_op
86 )
87 }
88
89 fn to_symbol(self) -> Option<&'static str> {
90 match self {
91 Self::EOI => None,
92 Self::whitespace => None,
93 Self::identifier_part => None,
94 Self::identifier => None,
95 Self::strict_identifier_part => None,
96 Self::strict_identifier => None,
97 Self::symbol => None,
98 Self::string_escape => None,
99 Self::string_content_char => None,
100 Self::string_content => None,
101 Self::string_literal => None,
102 Self::raw_string_content => None,
103 Self::raw_string_literal => None,
104 Self::at_op => Some("@"),
105 Self::pattern_kind_op => Some(":"),
106 Self::parents_op => Some("-"),
107 Self::children_op => Some("+"),
108 Self::compat_parents_op => Some("^"),
109 Self::dag_range_op
110 | Self::dag_range_pre_op
111 | Self::dag_range_post_op
112 | Self::dag_range_all_op => Some("::"),
113 Self::compat_dag_range_op
114 | Self::compat_dag_range_pre_op
115 | Self::compat_dag_range_post_op => Some(":"),
116 Self::range_op => Some(".."),
117 Self::range_pre_op | Self::range_post_op | Self::range_all_op => Some(".."),
118 Self::range_ops => None,
119 Self::range_pre_ops => None,
120 Self::range_post_ops => None,
121 Self::range_all_ops => None,
122 Self::negate_op => Some("~"),
123 Self::union_op => Some("|"),
124 Self::intersection_op => Some("&"),
125 Self::difference_op => Some("~"),
126 Self::compat_add_op => Some("+"),
127 Self::compat_sub_op => Some("-"),
128 Self::infix_op => None,
129 Self::function => None,
130 Self::function_name => None,
131 Self::keyword_argument => None,
132 Self::argument => None,
133 Self::function_arguments => None,
134 Self::formal_parameters => None,
135 Self::pattern => None,
136 Self::pattern_value_expression => None,
137 Self::primary => None,
138 Self::neighbors_expression => None,
139 Self::range_expression => None,
140 Self::expression => None,
141 Self::program => None,
142 Self::symbol_name => None,
143 Self::function_alias_declaration => None,
144 Self::pattern_alias_declaration => None,
145 Self::alias_declaration => None,
146 }
147 }
148}
149
150pub type RevsetDiagnostics = Diagnostics<RevsetParseError>;
153
154#[derive(Debug, Error)]
156#[error("{pest_error}")]
157pub struct RevsetParseError {
158 kind: Box<RevsetParseErrorKind>,
159 pest_error: Box<pest::error::Error<Rule>>,
160 source: Option<Box<dyn error::Error + Send + Sync>>,
161}
162
163#[derive(Debug, Error, PartialEq, Eq)]
164#[expect(missing_docs)]
165pub enum RevsetParseErrorKind {
166 #[error("Syntax error")]
167 SyntaxError,
168 #[error("`{op}` is not a prefix operator")]
169 NotPrefixOperator {
170 op: String,
171 similar_op: String,
172 description: String,
173 },
174 #[error("`{op}` is not a postfix operator")]
175 NotPostfixOperator {
176 op: String,
177 similar_op: String,
178 description: String,
179 },
180 #[error("`{op}` is not an infix operator")]
181 NotInfixOperator {
182 op: String,
183 similar_op: String,
184 description: String,
185 },
186 #[error("Function `{name}` doesn't exist")]
187 NoSuchFunction {
188 name: String,
189 candidates: Vec<String>,
190 },
191 #[error("Function `{name}`: {message}")]
192 InvalidFunctionArguments { name: String, message: String },
193 #[error("Cannot resolve file pattern without workspace")]
194 FsPathWithoutWorkspace,
195 #[error("Cannot resolve `@` without workspace")]
196 WorkingCopyWithoutWorkspace,
197 #[error("Redefinition of function parameter")]
198 RedefinedFunctionParameter,
199 #[error("{0}")]
200 Expression(String),
201 #[error("In alias `{0}`")]
202 InAliasExpansion(String),
203 #[error("In function parameter `{0}`")]
204 InParameterExpansion(String),
205 #[error("Alias `{0}` expanded recursively")]
206 RecursiveAlias(String),
207}
208
209impl RevsetParseError {
210 pub(super) fn with_span(kind: RevsetParseErrorKind, span: pest::Span<'_>) -> Self {
212 let message = kind.to_string();
213 let pest_error = Box::new(pest::error::Error::new_from_span(
214 pest::error::ErrorVariant::CustomError { message },
215 span,
216 ));
217 Self {
218 kind: Box::new(kind),
219 pest_error,
220 source: None,
221 }
222 }
223
224 pub(super) fn with_source(
226 mut self,
227 source: impl Into<Box<dyn error::Error + Send + Sync>>,
228 ) -> Self {
229 self.source = Some(source.into());
230 self
231 }
232
233 pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {
235 Self::with_span(RevsetParseErrorKind::Expression(message.into()), span)
236 }
237
238 pub(super) fn extend_function_candidates<I>(mut self, other_functions: I) -> Self
241 where
242 I: IntoIterator,
243 I::Item: AsRef<str>,
244 {
245 if let RevsetParseErrorKind::NoSuchFunction { name, candidates } = self.kind.as_mut() {
246 let other_candidates = collect_similar(name, other_functions);
247 *candidates = itertools::merge(mem::take(candidates), other_candidates)
248 .dedup()
249 .collect();
250 }
251 self
252 }
253
254 pub fn kind(&self) -> &RevsetParseErrorKind {
256 &self.kind
257 }
258
259 pub fn origin(&self) -> Option<&Self> {
261 self.source.as_ref().and_then(|e| e.downcast_ref())
262 }
263}
264
265impl AliasExpandError for RevsetParseError {
266 fn invalid_arguments(err: InvalidArguments<'_>) -> Self {
267 err.into()
268 }
269
270 fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self {
271 Self::with_span(RevsetParseErrorKind::RecursiveAlias(id.to_string()), span)
272 }
273
274 fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {
275 let kind = match id {
276 AliasId::Symbol(_) | AliasId::Pattern(..) | AliasId::Function(..) => {
277 RevsetParseErrorKind::InAliasExpansion(id.to_string())
278 }
279 AliasId::Parameter(_) => RevsetParseErrorKind::InParameterExpansion(id.to_string()),
280 };
281 Self::with_span(kind, span).with_source(self)
282 }
283}
284
285impl From<pest::error::Error<Rule>> for RevsetParseError {
286 fn from(err: pest::error::Error<Rule>) -> Self {
287 Self {
288 kind: Box::new(RevsetParseErrorKind::SyntaxError),
289 pest_error: Box::new(rename_rules_in_pest_error(err)),
290 source: None,
291 }
292 }
293}
294
295impl From<InvalidArguments<'_>> for RevsetParseError {
296 fn from(err: InvalidArguments<'_>) -> Self {
297 let kind = RevsetParseErrorKind::InvalidFunctionArguments {
298 name: err.name.to_owned(),
299 message: err.message,
300 };
301 Self::with_span(kind, err.span)
302 }
303}
304
305fn rename_rules_in_pest_error(mut err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {
306 let pest::error::ErrorVariant::ParsingError {
307 positives,
308 negatives,
309 } = &mut err.variant
310 else {
311 return err;
312 };
313
314 let mut known_syms = HashSet::new();
317 positives.retain(|rule| {
318 !rule.is_compat() && rule.to_symbol().is_none_or(|sym| known_syms.insert(sym))
319 });
320 let mut known_syms = HashSet::new();
321 negatives.retain(|rule| rule.to_symbol().is_none_or(|sym| known_syms.insert(sym)));
322 err.renamed_rules(|rule| {
323 rule.to_symbol()
324 .map(|sym| format!("`{sym}`"))
325 .unwrap_or_else(|| format!("<{rule:?}>"))
326 })
327}
328
329#[derive(Clone, Debug, Eq, PartialEq)]
331pub enum ExpressionKind<'i> {
332 Identifier(&'i str),
334 String(String),
336 Pattern(Box<PatternNode<'i>>),
338 RemoteSymbol(RemoteRefSymbolBuf),
340 AtWorkspace(String),
342 AtCurrentWorkspace,
344 DagRangeAll,
346 RangeAll,
348 Unary(UnaryOp, Box<ExpressionNode<'i>>),
350 Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),
352 UnionAll(Vec<ExpressionNode<'i>>),
354 FunctionCall(Box<FunctionCallNode<'i>>),
356 AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
358}
359
360impl<'i> FoldableExpression<'i> for ExpressionKind<'i> {
361 fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>
362 where
363 F: ExpressionFolder<'i, Self> + ?Sized,
364 {
365 match self {
366 Self::Identifier(name) => folder.fold_identifier(name, span),
367 Self::String(_) => Ok(self),
368 Self::Pattern(pattern) => folder.fold_pattern(pattern, span),
369 Self::RemoteSymbol(_)
370 | ExpressionKind::AtWorkspace(_)
371 | Self::AtCurrentWorkspace
372 | Self::DagRangeAll
373 | Self::RangeAll => Ok(self),
374 Self::Unary(op, arg) => {
375 let arg = Box::new(folder.fold_expression(*arg)?);
376 Ok(Self::Unary(op, arg))
377 }
378 Self::Binary(op, lhs, rhs) => {
379 let lhs = Box::new(folder.fold_expression(*lhs)?);
380 let rhs = Box::new(folder.fold_expression(*rhs)?);
381 Ok(Self::Binary(op, lhs, rhs))
382 }
383 Self::UnionAll(nodes) => {
384 let nodes = dsl_util::fold_expression_nodes(folder, nodes)?;
385 Ok(Self::UnionAll(nodes))
386 }
387 Self::FunctionCall(function) => folder.fold_function_call(function, span),
388 Self::AliasExpanded(id, subst) => {
389 let subst = Box::new(folder.fold_expression(*subst)?);
390 Ok(Self::AliasExpanded(id, subst))
391 }
392 }
393 }
394}
395
396impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {
397 fn identifier(name: &'i str) -> Self {
398 Self::Identifier(name)
399 }
400
401 fn pattern(pattern: Box<PatternNode<'i>>) -> Self {
402 Self::Pattern(pattern)
403 }
404
405 fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {
406 Self::FunctionCall(function)
407 }
408
409 fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {
410 Self::AliasExpanded(id, subst)
411 }
412}
413
414#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
416pub enum UnaryOp {
417 Negate,
419 DagRangePre,
421 DagRangePost,
423 RangePre,
425 RangePost,
427 Parents,
429 Children,
431}
432
433#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
435pub enum BinaryOp {
436 Intersection,
438 Difference,
440 DagRange,
442 Range,
444}
445
446pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>;
448pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>;
450pub type PatternNode<'i> = dsl_util::PatternNode<'i, ExpressionKind<'i>>;
452
453fn union_nodes<'i>(lhs: ExpressionNode<'i>, rhs: ExpressionNode<'i>) -> ExpressionNode<'i> {
454 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
455 let expr = match lhs.kind {
456 ExpressionKind::UnionAll(mut nodes) => {
459 nodes.push(rhs);
460 ExpressionKind::UnionAll(nodes)
461 }
462 _ => ExpressionKind::UnionAll(vec![lhs, rhs]),
463 };
464 ExpressionNode::new(expr, span)
465}
466
467pub fn parse_program(revset_str: &str) -> Result<ExpressionNode<'_>, RevsetParseError> {
469 let mut pairs = RevsetParser::parse(Rule::program, revset_str)?;
470 let first = pairs.next().unwrap();
471 assert_eq!(first.as_rule(), Rule::expression);
472 parse_expression_node(first)
473}
474
475fn parse_expression_node(pair: Pair<Rule>) -> Result<ExpressionNode, RevsetParseError> {
476 fn not_prefix_op(
477 op: &Pair<Rule>,
478 similar_op: impl Into<String>,
479 description: impl Into<String>,
480 ) -> RevsetParseError {
481 RevsetParseError::with_span(
482 RevsetParseErrorKind::NotPrefixOperator {
483 op: op.as_str().to_owned(),
484 similar_op: similar_op.into(),
485 description: description.into(),
486 },
487 op.as_span(),
488 )
489 }
490
491 fn not_postfix_op(
492 op: &Pair<Rule>,
493 similar_op: impl Into<String>,
494 description: impl Into<String>,
495 ) -> RevsetParseError {
496 RevsetParseError::with_span(
497 RevsetParseErrorKind::NotPostfixOperator {
498 op: op.as_str().to_owned(),
499 similar_op: similar_op.into(),
500 description: description.into(),
501 },
502 op.as_span(),
503 )
504 }
505
506 fn not_infix_op(
507 op: &Pair<Rule>,
508 similar_op: impl Into<String>,
509 description: impl Into<String>,
510 ) -> RevsetParseError {
511 RevsetParseError::with_span(
512 RevsetParseErrorKind::NotInfixOperator {
513 op: op.as_str().to_owned(),
514 similar_op: similar_op.into(),
515 description: description.into(),
516 },
517 op.as_span(),
518 )
519 }
520
521 static PRATT: LazyLock<PrattParser<Rule>> = LazyLock::new(|| {
522 PrattParser::new()
523 .op(Op::infix(Rule::union_op, Assoc::Left)
524 | Op::infix(Rule::compat_add_op, Assoc::Left))
525 .op(Op::infix(Rule::intersection_op, Assoc::Left)
526 | Op::infix(Rule::difference_op, Assoc::Left)
527 | Op::infix(Rule::compat_sub_op, Assoc::Left))
528 .op(Op::prefix(Rule::negate_op))
529 .op(Op::infix(Rule::dag_range_op, Assoc::Left)
531 | Op::infix(Rule::compat_dag_range_op, Assoc::Left)
532 | Op::infix(Rule::range_op, Assoc::Left))
533 .op(Op::prefix(Rule::dag_range_pre_op)
534 | Op::prefix(Rule::compat_dag_range_pre_op)
535 | Op::prefix(Rule::range_pre_op))
536 .op(Op::postfix(Rule::dag_range_post_op)
537 | Op::postfix(Rule::compat_dag_range_post_op)
538 | Op::postfix(Rule::range_post_op))
539 .op(Op::postfix(Rule::parents_op)
541 | Op::postfix(Rule::children_op)
542 | Op::postfix(Rule::compat_parents_op))
543 });
544 PRATT
545 .map_primary(|primary| {
546 let expr = match primary.as_rule() {
547 Rule::primary => return parse_primary_node(primary),
548 Rule::dag_range_all_op => ExpressionKind::DagRangeAll,
549 Rule::range_all_op => ExpressionKind::RangeAll,
550 r => panic!("unexpected primary rule {r:?}"),
551 };
552 Ok(ExpressionNode::new(expr, primary.as_span()))
553 })
554 .map_prefix(|op, rhs| {
555 let op_kind = match op.as_rule() {
556 Rule::negate_op => UnaryOp::Negate,
557 Rule::dag_range_pre_op => UnaryOp::DagRangePre,
558 Rule::compat_dag_range_pre_op => Err(not_prefix_op(&op, "::", "ancestors"))?,
559 Rule::range_pre_op => UnaryOp::RangePre,
560 r => panic!("unexpected prefix operator rule {r:?}"),
561 };
562 let rhs = Box::new(rhs?);
563 let span = op.as_span().start_pos().span(&rhs.span.end_pos());
564 let expr = ExpressionKind::Unary(op_kind, rhs);
565 Ok(ExpressionNode::new(expr, span))
566 })
567 .map_postfix(|lhs, op| {
568 let op_kind = match op.as_rule() {
569 Rule::dag_range_post_op => UnaryOp::DagRangePost,
570 Rule::compat_dag_range_post_op => Err(not_postfix_op(&op, "::", "descendants"))?,
571 Rule::range_post_op => UnaryOp::RangePost,
572 Rule::parents_op => UnaryOp::Parents,
573 Rule::children_op => UnaryOp::Children,
574 Rule::compat_parents_op => Err(not_postfix_op(&op, "-", "parents"))?,
575 r => panic!("unexpected postfix operator rule {r:?}"),
576 };
577 let lhs = Box::new(lhs?);
578 let span = lhs.span.start_pos().span(&op.as_span().end_pos());
579 let expr = ExpressionKind::Unary(op_kind, lhs);
580 Ok(ExpressionNode::new(expr, span))
581 })
582 .map_infix(|lhs, op, rhs| {
583 let op_kind = match op.as_rule() {
584 Rule::union_op => return Ok(union_nodes(lhs?, rhs?)),
585 Rule::compat_add_op => Err(not_infix_op(&op, "|", "union"))?,
586 Rule::intersection_op => BinaryOp::Intersection,
587 Rule::difference_op => BinaryOp::Difference,
588 Rule::compat_sub_op => Err(not_infix_op(&op, "~", "difference"))?,
589 Rule::dag_range_op => BinaryOp::DagRange,
590 Rule::compat_dag_range_op => Err(not_infix_op(&op, "::", "DAG range"))?,
591 Rule::range_op => BinaryOp::Range,
592 r => panic!("unexpected infix operator rule {r:?}"),
593 };
594 let lhs = Box::new(lhs?);
595 let rhs = Box::new(rhs?);
596 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
597 let expr = ExpressionKind::Binary(op_kind, lhs, rhs);
598 Ok(ExpressionNode::new(expr, span))
599 })
600 .parse(pair.into_inner())
601}
602
603fn parse_primary_node(pair: Pair<Rule>) -> Result<ExpressionNode, RevsetParseError> {
604 let span = pair.as_span();
605 let mut pairs = pair.into_inner();
606 let first = pairs.next().unwrap();
607 let expr = match first.as_rule() {
608 Rule::expression => parse_expression_node(first)?.kind,
610 Rule::function => {
611 let function = Box::new(FUNCTION_CALL_PARSER.parse(
612 first,
613 |pair| Ok(pair.as_str()),
614 |pair| parse_expression_node(pair),
615 )?);
616 ExpressionKind::FunctionCall(function)
617 }
618 Rule::pattern => {
619 let [lhs, op, rhs] = first.into_inner().collect_array().unwrap();
620 assert_eq!(lhs.as_rule(), Rule::strict_identifier);
621 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
622 assert_eq!(rhs.as_rule(), Rule::pattern_value_expression);
623 let pattern = Box::new(PatternNode {
624 name: lhs.as_str(),
625 name_span: lhs.as_span(),
626 value: parse_expression_node(rhs)?,
627 });
628 ExpressionKind::Pattern(pattern)
629 }
630 Rule::identifier if pairs.peek().is_none() => ExpressionKind::Identifier(first.as_str()),
633 Rule::identifier | Rule::string_literal | Rule::raw_string_literal => {
634 let name = parse_as_string_literal(first);
635 match pairs.next() {
636 None => ExpressionKind::String(name),
637 Some(op) => {
638 assert_eq!(op.as_rule(), Rule::at_op);
639 match pairs.next() {
640 None => ExpressionKind::AtWorkspace(name),
642 Some(second) => {
644 let name: RefNameBuf = name.into();
645 let remote: RemoteNameBuf = parse_as_string_literal(second).into();
646 ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf { name, remote })
647 }
648 }
649 }
650 }
651 }
652 Rule::at_op => ExpressionKind::AtCurrentWorkspace,
654 r => panic!("unexpected revset parse rule: {r:?}"),
655 };
656 Ok(ExpressionNode::new(expr, span))
657}
658
659fn parse_as_string_literal(pair: Pair<Rule>) -> String {
661 match pair.as_rule() {
662 Rule::identifier => pair.as_str().to_owned(),
663 Rule::string_literal => STRING_LITERAL_PARSER.parse(pair.into_inner()),
664 Rule::raw_string_literal => {
665 let [content] = pair.into_inner().collect_array().unwrap();
666 assert_eq!(content.as_rule(), Rule::raw_string_content);
667 content.as_str().to_owned()
668 }
669 _ => {
670 panic!("unexpected string literal rule: {:?}", pair.as_str());
671 }
672 }
673}
674
675pub fn is_identifier(text: &str) -> bool {
677 match RevsetParser::parse(Rule::identifier, text) {
678 Ok(mut pairs) => pairs.next().unwrap().as_span().end() == text.len(),
679 Err(_) => false,
680 }
681}
682
683pub fn parse_symbol(text: &str) -> Result<String, RevsetParseError> {
685 let mut pairs = RevsetParser::parse(Rule::symbol_name, text)?;
686 let first = pairs.next().unwrap();
687 let span = first.as_span();
688 let name = parse_as_string_literal(first);
689 if name.is_empty() {
690 Err(RevsetParseError::expression(
691 "Expected non-empty string",
692 span,
693 ))
694 } else {
695 Ok(name)
696 }
697}
698
699pub fn format_symbol(literal: &str) -> String {
705 if is_identifier(literal) {
706 literal.to_string()
707 } else {
708 format_string(literal)
709 }
710}
711
712pub fn format_remote_symbol(name: &str, remote: &str) -> String {
714 let name = format_symbol(name);
715 let remote = format_symbol(remote);
716 format!("{name}@{remote}")
717}
718
719pub fn new_string_node(content: &str) -> ExpressionNode<'_> {
721 ExpressionNode {
722 kind: ExpressionKind::String(content.to_owned()),
723 span: pest::Span::new(content, 0, content.len()).expect("total span must be valid"),
724 }
725}
726
727pub type RevsetAliasesMap = AliasesMap<RevsetAliasParser, String>;
729
730#[derive(Clone, Debug, Default)]
732pub struct RevsetAliasParser;
733
734impl AliasDeclarationParser for RevsetAliasParser {
735 type Error = RevsetParseError;
736
737 fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> {
738 let mut pairs = RevsetParser::parse(Rule::alias_declaration, source)?;
739 let first = pairs.next().unwrap();
740 match first.as_rule() {
741 Rule::strict_identifier => Ok(AliasDeclaration::Symbol(first.as_str().to_owned())),
742 Rule::pattern_alias_declaration => {
743 let [name_pair, op, param_pair] = first.into_inner().collect_array().unwrap();
744 assert_eq!(name_pair.as_rule(), Rule::strict_identifier);
745 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
746 assert_eq!(param_pair.as_rule(), Rule::strict_identifier);
747 let name = name_pair.as_str().to_owned();
748 let param = param_pair.as_str().to_owned();
749 Ok(AliasDeclaration::Pattern(name, param))
750 }
751 Rule::function_alias_declaration => {
752 let [name_pair, params_pair] = first.into_inner().collect_array().unwrap();
753 assert_eq!(name_pair.as_rule(), Rule::function_name);
754 assert_eq!(params_pair.as_rule(), Rule::formal_parameters);
755 let name = name_pair.as_str().to_owned();
756 let params_span = params_pair.as_span();
757 let params = params_pair
758 .into_inner()
759 .map(|pair| match pair.as_rule() {
760 Rule::strict_identifier => pair.as_str().to_owned(),
761 r => panic!("unexpected formal parameter rule {r:?}"),
762 })
763 .collect_vec();
764 if params.iter().all_unique() {
765 Ok(AliasDeclaration::Function(name, params))
766 } else {
767 Err(RevsetParseError::with_span(
768 RevsetParseErrorKind::RedefinedFunctionParameter,
769 params_span,
770 ))
771 }
772 }
773 r => panic!("unexpected alias declaration rule {r:?}"),
774 }
775 }
776}
777
778impl AliasDefinitionParser for RevsetAliasParser {
779 type Output<'i> = ExpressionKind<'i>;
780 type Error = RevsetParseError;
781
782 fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> {
783 parse_program(source)
784 }
785}
786
787pub(super) fn expect_string_pattern<'a>(
790 type_name: &str,
791 node: &'a ExpressionNode<'_>,
792) -> Result<(&'a str, Option<&'a str>), RevsetParseError> {
793 catch_aliases_no_diagnostics(node, |node| match &node.kind {
794 ExpressionKind::Identifier(name) => Ok((*name, None)),
795 ExpressionKind::String(name) => Ok((name, None)),
796 ExpressionKind::Pattern(pattern) => {
797 let value = expect_string_literal("string", &pattern.value)?;
798 Ok((value, Some(pattern.name)))
799 }
800 _ => Err(RevsetParseError::expression(
801 format!("Expected {type_name}"),
802 node.span,
803 )),
804 })
805}
806
807pub fn expect_literal<T: FromStr>(
809 type_name: &str,
810 node: &ExpressionNode,
811) -> Result<T, RevsetParseError> {
812 catch_aliases_no_diagnostics(node, |node| {
813 let value = expect_string_literal(type_name, node)?;
814 value
815 .parse()
816 .map_err(|_| RevsetParseError::expression(format!("Expected {type_name}"), node.span))
817 })
818}
819
820pub(super) fn expect_string_literal<'a>(
822 type_name: &str,
823 node: &'a ExpressionNode<'_>,
824) -> Result<&'a str, RevsetParseError> {
825 catch_aliases_no_diagnostics(node, |node| match &node.kind {
826 ExpressionKind::Identifier(name) => Ok(*name),
827 ExpressionKind::String(name) => Ok(name),
828 _ => Err(RevsetParseError::expression(
829 format!("Expected {type_name}"),
830 node.span,
831 )),
832 })
833}
834
835pub(super) fn catch_aliases<'a, 'i, T>(
838 diagnostics: &mut RevsetDiagnostics,
839 node: &'a ExpressionNode<'i>,
840 f: impl FnOnce(&mut RevsetDiagnostics, &'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
841) -> Result<T, RevsetParseError> {
842 let (node, stack) = skip_aliases(node);
843 if stack.is_empty() {
844 f(diagnostics, node)
845 } else {
846 let mut inner_diagnostics = RevsetDiagnostics::new();
847 let result = f(&mut inner_diagnostics, node);
848 diagnostics.extend_with(inner_diagnostics, |diag| attach_aliases_err(diag, &stack));
849 result.map_err(|err| attach_aliases_err(err, &stack))
850 }
851}
852
853fn catch_aliases_no_diagnostics<'a, 'i, T>(
854 node: &'a ExpressionNode<'i>,
855 f: impl FnOnce(&'a ExpressionNode<'i>) -> Result<T, RevsetParseError>,
856) -> Result<T, RevsetParseError> {
857 let (node, stack) = skip_aliases(node);
858 f(node).map_err(|err| attach_aliases_err(err, &stack))
859}
860
861fn skip_aliases<'a, 'i>(
862 mut node: &'a ExpressionNode<'i>,
863) -> (&'a ExpressionNode<'i>, Vec<(AliasId<'i>, pest::Span<'i>)>) {
864 let mut stack = Vec::new();
865 while let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
866 stack.push((*id, node.span));
867 node = subst;
868 }
869 (node, stack)
870}
871
872fn attach_aliases_err(
873 err: RevsetParseError,
874 stack: &[(AliasId<'_>, pest::Span<'_>)],
875) -> RevsetParseError {
876 stack
877 .iter()
878 .rfold(err, |err, &(id, span)| err.within_alias_expansion(id, span))
879}
880
881#[cfg(test)]
882mod tests {
883 use std::assert_matches;
884 use std::collections::HashMap;
885
886 use super::*;
887 use crate::dsl_util::KeywordArgument;
888 use crate::tests::TestResult;
889
890 #[derive(Debug)]
891 struct WithRevsetAliasesMap<'i> {
892 aliases_map: RevsetAliasesMap,
893 locals: HashMap<&'i str, ExpressionNode<'i>>,
894 }
895
896 impl<'i> WithRevsetAliasesMap<'i> {
897 fn set_local(mut self, name: &'i str, value: &'i str) -> Self {
898 self.locals.insert(name, parse_program(value).unwrap());
899 self
900 }
901
902 fn parse(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> {
903 let node = parse_program(text)?;
904 dsl_util::expand_aliases_with_locals(node, &self.aliases_map, &self.locals)
905 }
906
907 fn parse_normalized(&'i self, text: &'i str) -> ExpressionNode<'i> {
908 normalize_tree(self.parse(text).unwrap())
909 }
910 }
911
912 fn with_aliases<'i>(
913 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
914 ) -> WithRevsetAliasesMap<'i> {
915 let mut aliases_map = RevsetAliasesMap::new();
916 for (decl, defn) in aliases {
917 aliases_map.insert(decl, defn, None).unwrap();
918 }
919 WithRevsetAliasesMap {
920 aliases_map,
921 locals: HashMap::new(),
922 }
923 }
924
925 fn parse_into_kind(text: &str) -> Result<ExpressionKind<'_>, RevsetParseErrorKind> {
926 parse_program(text)
927 .map(|node| node.kind)
928 .map_err(|err| *err.kind)
929 }
930
931 fn parse_normalized(text: &str) -> ExpressionNode<'_> {
932 normalize_tree(parse_program(text).unwrap())
933 }
934
935 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
937 fn empty_span() -> pest::Span<'static> {
938 pest::Span::new("", 0, 0).unwrap()
939 }
940
941 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
942 nodes.into_iter().map(normalize_tree).collect()
943 }
944
945 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
946 FunctionCallNode {
947 name: function.name,
948 name_span: empty_span(),
949 args: normalize_list(function.args),
950 keyword_args: function
951 .keyword_args
952 .into_iter()
953 .map(|arg| KeywordArgument {
954 name: arg.name,
955 name_span: empty_span(),
956 value: normalize_tree(arg.value),
957 })
958 .collect(),
959 args_span: empty_span(),
960 }
961 }
962
963 let normalized_kind = match node.kind {
964 ExpressionKind::Identifier(_) | ExpressionKind::String(_) => node.kind,
965 ExpressionKind::Pattern(pattern) => {
966 let pattern = Box::new(PatternNode {
967 name: pattern.name,
968 name_span: empty_span(),
969 value: normalize_tree(pattern.value),
970 });
971 ExpressionKind::Pattern(pattern)
972 }
973 ExpressionKind::RemoteSymbol(_)
974 | ExpressionKind::AtWorkspace(_)
975 | ExpressionKind::AtCurrentWorkspace
976 | ExpressionKind::DagRangeAll
977 | ExpressionKind::RangeAll => node.kind,
978 ExpressionKind::Unary(op, arg) => {
979 let arg = Box::new(normalize_tree(*arg));
980 ExpressionKind::Unary(op, arg)
981 }
982 ExpressionKind::Binary(op, lhs, rhs) => {
983 let lhs = Box::new(normalize_tree(*lhs));
984 let rhs = Box::new(normalize_tree(*rhs));
985 ExpressionKind::Binary(op, lhs, rhs)
986 }
987 ExpressionKind::UnionAll(nodes) => {
988 let nodes = normalize_list(nodes);
989 ExpressionKind::UnionAll(nodes)
990 }
991 ExpressionKind::FunctionCall(function) => {
992 let function = Box::new(normalize_function_call(*function));
993 ExpressionKind::FunctionCall(function)
994 }
995 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
996 };
997 ExpressionNode {
998 kind: normalized_kind,
999 span: empty_span(),
1000 }
1001 }
1002
1003 #[test]
1004 fn test_parse_tree_eq() {
1005 assert_eq!(
1006 parse_normalized(r#" foo( x ) | ~bar:"baz" "#),
1007 parse_normalized(r#"(foo(x))|(~(bar:"baz"))"#)
1008 );
1009 assert_ne!(parse_normalized(r#" foo "#), parse_normalized(r#" "foo" "#));
1010 }
1011
1012 #[test]
1013 fn test_parse_revset() -> TestResult {
1014 assert_eq!(
1016 parse_into_kind("\"foo\""),
1017 Ok(ExpressionKind::String("foo".to_owned()))
1018 );
1019 assert_eq!(
1020 parse_into_kind("'foo'"),
1021 Ok(ExpressionKind::String("foo".to_owned()))
1022 );
1023 assert_matches!(
1025 parse_into_kind("foo-"),
1026 Ok(ExpressionKind::Unary(UnaryOp::Parents, _))
1027 );
1028 assert_matches!(
1030 parse_into_kind("foo+"),
1031 Ok(ExpressionKind::Unary(UnaryOp::Children, _))
1032 );
1033 assert_matches!(
1035 parse_into_kind("::foo"),
1036 Ok(ExpressionKind::Unary(UnaryOp::DagRangePre, _))
1037 );
1038 assert_matches!(
1040 parse_into_kind("foo::"),
1041 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1042 );
1043 assert_matches!(
1045 parse_into_kind("foo::bar"),
1046 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1047 );
1048 assert_matches!(parse_into_kind("::"), Ok(ExpressionKind::DagRangeAll));
1050 assert_matches!(
1052 parse_into_kind("..foo"),
1053 Ok(ExpressionKind::Unary(UnaryOp::RangePre, _))
1054 );
1055 assert_matches!(
1056 parse_into_kind("foo.."),
1057 Ok(ExpressionKind::Unary(UnaryOp::RangePost, _))
1058 );
1059 assert_matches!(
1060 parse_into_kind("foo..bar"),
1061 Ok(ExpressionKind::Binary(BinaryOp::Range, _, _))
1062 );
1063 assert_matches!(parse_into_kind(".."), Ok(ExpressionKind::RangeAll));
1065 assert_matches!(
1067 parse_into_kind("~ foo"),
1068 Ok(ExpressionKind::Unary(UnaryOp::Negate, _))
1069 );
1070 assert_eq!(
1071 parse_normalized("~ ~~ foo"),
1072 parse_normalized("~(~(~(foo)))"),
1073 );
1074 assert_matches!(
1076 parse_into_kind("foo & bar"),
1077 Ok(ExpressionKind::Binary(BinaryOp::Intersection, _, _))
1078 );
1079 assert_matches!(
1081 parse_into_kind("foo | bar"),
1082 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 2
1083 );
1084 assert_matches!(
1085 parse_into_kind("foo | bar | baz"),
1086 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 3
1087 );
1088 assert_matches!(
1090 parse_into_kind("foo ~ bar"),
1091 Ok(ExpressionKind::Binary(BinaryOp::Difference, _, _))
1092 );
1093 assert_eq!(parse_normalized("(foo)-"), parse_normalized("foo-"));
1095 assert_eq!(parse_normalized(" ::foo "), parse_normalized("::foo"));
1097 assert_eq!(parse_normalized("( ::foo )"), parse_normalized("::foo"));
1098 assert_eq!(
1100 parse_into_kind(" :: foo "),
1101 Err(RevsetParseErrorKind::SyntaxError)
1102 );
1103 assert_eq!(
1105 parse_into_kind("foo | -"),
1106 Err(RevsetParseErrorKind::SyntaxError)
1107 );
1108
1109 assert_eq!(parse_program(" ~ x ")?.span.as_str(), "~ x");
1111 assert_eq!(parse_program(" x+ ")?.span.as_str(), "x+");
1112 assert_eq!(parse_program(" x |y ")?.span.as_str(), "x |y");
1113 assert_eq!(parse_program(" (x) ")?.span.as_str(), "(x)");
1114 assert_eq!(parse_program("~( x|y) ")?.span.as_str(), "~( x|y)");
1115 assert_eq!(parse_program(" ( x )- ")?.span.as_str(), "( x )-");
1116 Ok(())
1117 }
1118
1119 #[test]
1120 fn test_parse_whitespace() {
1121 let ascii_whitespaces: String = ('\x00'..='\x7f')
1122 .filter(char::is_ascii_whitespace)
1123 .collect();
1124 assert_eq!(
1125 parse_normalized(&format!("{ascii_whitespaces}all()")),
1126 parse_normalized("all()"),
1127 );
1128 }
1129
1130 #[test]
1131 fn test_parse_identifier() {
1132 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Identifier("0")));
1134 assert_eq!(
1136 parse_into_kind("foo_bar/baz"),
1137 Ok(ExpressionKind::Identifier("foo_bar/baz"))
1138 );
1139 assert_eq!(
1141 parse_into_kind("*/foo/**"),
1142 Ok(ExpressionKind::Identifier("*/foo/**"))
1143 );
1144
1145 assert_eq!(
1147 parse_into_kind("foo.bar-v1+7"),
1148 Ok(ExpressionKind::Identifier("foo.bar-v1+7"))
1149 );
1150 assert_eq!(
1151 parse_normalized("foo.bar-v1+7-"),
1152 parse_normalized("(foo.bar-v1+7)-")
1153 );
1154 assert_eq!(
1156 parse_into_kind("foo--bar"),
1157 Ok(ExpressionKind::Identifier("foo--bar"))
1158 );
1159 assert_eq!(
1160 parse_into_kind("foo----bar"),
1161 Ok(ExpressionKind::Identifier("foo----bar"))
1162 );
1163 assert_eq!(
1165 parse_into_kind(".foo"),
1166 Err(RevsetParseErrorKind::SyntaxError)
1167 );
1168 assert_eq!(
1169 parse_into_kind("foo."),
1170 Err(RevsetParseErrorKind::SyntaxError)
1171 );
1172 assert_eq!(
1174 parse_into_kind("foo.+bar"),
1175 Err(RevsetParseErrorKind::SyntaxError)
1176 );
1177 assert_eq!(
1178 parse_into_kind("foo++bar"),
1179 Err(RevsetParseErrorKind::SyntaxError)
1180 );
1181 assert_eq!(
1182 parse_into_kind("foo+-bar"),
1183 Err(RevsetParseErrorKind::SyntaxError)
1184 );
1185
1186 assert_eq!(parse_normalized("(foo)"), parse_normalized("foo"));
1188
1189 assert_eq!(
1191 parse_into_kind("柔術+jj"),
1192 Ok(ExpressionKind::Identifier("柔術+jj"))
1193 );
1194 }
1195
1196 #[test]
1197 fn test_parse_string_literal() {
1198 assert_eq!(
1200 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1201 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned()))
1202 );
1203
1204 assert_eq!(
1206 parse_into_kind(r#" "\y" "#),
1207 Err(RevsetParseErrorKind::SyntaxError)
1208 );
1209
1210 assert_eq!(
1212 parse_into_kind(r#" '' "#),
1213 Ok(ExpressionKind::String("".to_owned()))
1214 );
1215 assert_eq!(
1216 parse_into_kind(r#" 'a\n' "#),
1217 Ok(ExpressionKind::String(r"a\n".to_owned()))
1218 );
1219 assert_eq!(
1220 parse_into_kind(r#" '\' "#),
1221 Ok(ExpressionKind::String(r"\".to_owned()))
1222 );
1223 assert_eq!(
1224 parse_into_kind(r#" '"' "#),
1225 Ok(ExpressionKind::String(r#"""#.to_owned()))
1226 );
1227
1228 assert_eq!(
1230 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1231 Ok(ExpressionKind::String("aeiou".to_owned()))
1232 );
1233 assert_eq!(
1234 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1235 Ok(ExpressionKind::String("àèìðù".to_owned()))
1236 );
1237 assert_eq!(
1238 parse_into_kind(r#""\x""#),
1239 Err(RevsetParseErrorKind::SyntaxError)
1240 );
1241 assert_eq!(
1242 parse_into_kind(r#""\xf""#),
1243 Err(RevsetParseErrorKind::SyntaxError)
1244 );
1245 assert_eq!(
1246 parse_into_kind(r#""\xgg""#),
1247 Err(RevsetParseErrorKind::SyntaxError)
1248 );
1249 }
1250
1251 #[test]
1252 fn test_parse_pattern() -> TestResult {
1253 fn unwrap_pattern(kind: ExpressionKind<'_>) -> (&str, ExpressionKind<'_>) {
1254 match kind {
1255 ExpressionKind::Pattern(pattern) => (pattern.name, pattern.value.kind),
1256 _ => panic!("unexpected expression: {kind:?}"),
1257 }
1258 }
1259
1260 assert_eq!(
1261 unwrap_pattern(parse_into_kind(r#"substring:"foo""#)?),
1262 ("substring", ExpressionKind::String("foo".to_owned()))
1263 );
1264 assert_eq!(
1265 unwrap_pattern(parse_into_kind("exact:foo")?),
1266 ("exact", ExpressionKind::Identifier("foo"))
1267 );
1268 assert_eq!(
1269 parse_into_kind(r#""exact:foo""#),
1270 Ok(ExpressionKind::String("exact:foo".to_owned()))
1271 );
1272 assert_eq!(
1274 unwrap_pattern(parse_into_kind("x:@")?),
1275 ("x", ExpressionKind::AtCurrentWorkspace)
1276 );
1277 assert_eq!(
1278 unwrap_pattern(parse_into_kind("x:y@z")?),
1279 (
1280 "x",
1281 ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1282 name: "y".into(),
1283 remote: "z".into(),
1284 })
1285 )
1286 );
1287
1288 assert_eq!(
1289 parse_normalized(r#"(exact:"foo" )"#),
1290 parse_normalized(r#"(exact:"foo")"#),
1291 );
1292 assert_eq!(
1293 unwrap_pattern(parse_into_kind(r#"exact:'\'"#)?),
1294 ("exact", ExpressionKind::String(r"\".to_owned()))
1295 );
1296
1297 assert_matches!(
1299 parse_into_kind("exact: foo"),
1300 Err(RevsetParseErrorKind::SyntaxError)
1301 );
1302 assert_matches!(
1303 parse_into_kind("exact :foo"),
1304 Err(RevsetParseErrorKind::SyntaxError)
1305 );
1306 assert_eq!(
1308 parse_normalized("exact:( 'foo' )"),
1309 parse_normalized("exact:'foo'"),
1310 );
1311
1312 assert_eq!(parse_normalized("x:f(y)"), parse_normalized("x:(f(y))"));
1314 assert_eq!(parse_normalized("x:@-+"), parse_normalized("x:((@-)+)"));
1316 assert_eq!(parse_normalized("x:y::z"), parse_normalized("(x:y)::(z)"));
1319 assert_matches!(
1320 parse_into_kind("x:::"),
1321 Err(RevsetParseErrorKind::SyntaxError)
1322 );
1323 assert_eq!(parse_normalized("x:y&z"), parse_normalized("(x:y)&(z)"));
1325 assert_matches!(
1326 parse_into_kind("x:~y"), Err(RevsetParseErrorKind::NotPostfixOperator { .. })
1328 );
1329
1330 assert_eq!(parse_normalized("x:y:z"), parse_normalized("x:(y:z)"));
1332 Ok(())
1333 }
1334
1335 #[test]
1336 fn test_parse_symbol_explicitly() {
1337 assert_matches!(parse_symbol("").as_deref(), Err(_));
1338 assert_matches!(parse_symbol("''").as_deref(), Err(_));
1341
1342 assert_matches!(parse_symbol("foo.bar").as_deref(), Ok("foo.bar"));
1343 assert_matches!(parse_symbol("foo@bar").as_deref(), Err(_));
1344 assert_matches!(parse_symbol("foo bar").as_deref(), Err(_));
1345
1346 assert_matches!(parse_symbol("'foo bar'").as_deref(), Ok("foo bar"));
1347 assert_matches!(parse_symbol(r#""foo\tbar""#).as_deref(), Ok("foo\tbar"));
1348
1349 assert_matches!(parse_symbol(" foo").as_deref(), Err(_));
1351 assert_matches!(parse_symbol("foo ").as_deref(), Err(_));
1352
1353 assert_matches!(parse_symbol("(foo)").as_deref(), Err(_));
1356 }
1357
1358 #[test]
1359 fn parse_at_workspace_and_remote_symbol() {
1360 assert_eq!(parse_into_kind("@"), Ok(ExpressionKind::AtCurrentWorkspace));
1362 assert_eq!(
1363 parse_into_kind("main@"),
1364 Ok(ExpressionKind::AtWorkspace("main".to_owned()))
1365 );
1366 assert_eq!(
1367 parse_into_kind("main@origin"),
1368 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1369 name: "main".into(),
1370 remote: "origin".into()
1371 }))
1372 );
1373
1374 assert_eq!(
1376 parse_into_kind(r#""foo bar"@"#),
1377 Ok(ExpressionKind::AtWorkspace("foo bar".to_owned()))
1378 );
1379 assert_eq!(
1380 parse_into_kind(r#""foo bar"@origin"#),
1381 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1382 name: "foo bar".into(),
1383 remote: "origin".into()
1384 }))
1385 );
1386 assert_eq!(
1387 parse_into_kind(r#"main@"foo bar""#),
1388 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1389 name: "main".into(),
1390 remote: "foo bar".into()
1391 }))
1392 );
1393 assert_eq!(
1394 parse_into_kind(r#"'foo bar'@'bar baz'"#),
1395 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1396 name: "foo bar".into(),
1397 remote: "bar baz".into()
1398 }))
1399 );
1400
1401 assert_eq!(
1403 parse_into_kind(r#""@""#),
1404 Ok(ExpressionKind::String("@".to_owned()))
1405 );
1406 assert_eq!(
1407 parse_into_kind(r#""main@""#),
1408 Ok(ExpressionKind::String("main@".to_owned()))
1409 );
1410 assert_eq!(
1411 parse_into_kind(r#""main@origin""#),
1412 Ok(ExpressionKind::String("main@origin".to_owned()))
1413 );
1414
1415 assert_eq!(
1417 parse_into_kind("柔術@"),
1418 Ok(ExpressionKind::AtWorkspace("柔術".to_owned()))
1419 );
1420 assert_eq!(
1421 parse_into_kind("柔@術"),
1422 Ok(ExpressionKind::RemoteSymbol(RemoteRefSymbolBuf {
1423 name: "柔".into(),
1424 remote: "術".into()
1425 }))
1426 );
1427 }
1428
1429 #[test]
1430 fn test_parse_function_call() -> TestResult {
1431 fn unwrap_function_call(node: ExpressionNode<'_>) -> Box<FunctionCallNode<'_>> {
1432 match node.kind {
1433 ExpressionKind::FunctionCall(function) => function,
1434 _ => panic!("unexpected expression: {node:?}"),
1435 }
1436 }
1437
1438 assert_eq!(
1440 parse_normalized(
1441 " description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) ",
1442 ),
1443 parse_normalized("(description(arg1) ~ file(arg1, arg2)) ~ visible_heads()"),
1444 );
1445 assert_eq!(
1447 parse_normalized("remote_bookmarks( remote = foo )"),
1448 parse_normalized("remote_bookmarks(remote=foo)"),
1449 );
1450
1451 assert!(parse_into_kind("bookmarks(,)").is_err());
1453 assert_eq!(
1455 parse_normalized("bookmarks(a,)"),
1456 parse_normalized("bookmarks(a)")
1457 );
1458 assert_eq!(
1459 parse_normalized("bookmarks(a , )"),
1460 parse_normalized("bookmarks(a)")
1461 );
1462 assert!(parse_into_kind("bookmarks(,a)").is_err());
1463 assert!(parse_into_kind("bookmarks(a,,)").is_err());
1464 assert!(parse_into_kind("bookmarks(a , , )").is_err());
1465 assert_eq!(
1466 parse_normalized("file(a,b,)"),
1467 parse_normalized("file(a, b)")
1468 );
1469 assert!(parse_into_kind("file(a,,b)").is_err());
1470 assert_eq!(
1471 parse_normalized("remote_bookmarks(a,remote=b , )"),
1472 parse_normalized("remote_bookmarks(a, remote=b)"),
1473 );
1474 assert!(parse_into_kind("remote_bookmarks(a,,remote=b)").is_err());
1475
1476 let function = unwrap_function_call(parse_program("foo( a, (b) , ~(c), d = (e) )")?);
1478 assert_eq!(function.name_span.as_str(), "foo");
1479 assert_eq!(function.args_span.as_str(), "a, (b) , ~(c), d = (e)");
1480 assert_eq!(function.args[0].span.as_str(), "a");
1481 assert_eq!(function.args[1].span.as_str(), "(b)");
1482 assert_eq!(function.args[2].span.as_str(), "~(c)");
1483 assert_eq!(function.keyword_args[0].name_span.as_str(), "d");
1484 assert_eq!(function.keyword_args[0].value.span.as_str(), "(e)");
1485 Ok(())
1486 }
1487
1488 #[test]
1489 fn test_parse_revset_alias_symbol_decl() {
1490 let mut aliases_map = RevsetAliasesMap::new();
1491 assert!(aliases_map.insert("@", "none()", None).is_err());
1493 assert!(aliases_map.insert("a@", "none()", None).is_err());
1494 assert!(aliases_map.insert("a@b", "none()", None).is_err());
1495 assert!(aliases_map.insert("柔術", "none()", None).is_err());
1498 }
1499
1500 #[test]
1501 fn test_parse_revset_alias_pattern_decl() -> TestResult {
1502 let mut aliases_map = RevsetAliasesMap::new();
1503 assert!(aliases_map.insert("foo:", "none()", None).is_err());
1504 assert_eq!(aliases_map.pattern_names().count(), 0);
1505
1506 aliases_map.insert("bar:baz", "'bar pattern'", None)?;
1507 assert_eq!(aliases_map.pattern_names().count(), 1);
1508 let (id, param, defn, _doc) = aliases_map.get_pattern("bar").unwrap();
1509 assert_eq!(id, AliasId::Pattern("bar", "baz"));
1510 assert_eq!(param, "baz");
1511 assert_eq!(defn, "'bar pattern'");
1512
1513 assert!(aliases_map.insert("柔術:x", "none()", None).is_err());
1516 assert!(aliases_map.insert("x:柔術", "none()", None).is_err());
1517 Ok(())
1518 }
1519
1520 #[test]
1521 fn test_parse_revset_alias_func_decl() -> TestResult {
1522 let mut aliases_map = RevsetAliasesMap::new();
1523 assert!(
1524 aliases_map
1525 .insert("5func()", r#""is function 0""#, None)
1526 .is_err()
1527 );
1528 aliases_map.insert("func()", r#""is function 0""#, None)?;
1529 aliases_map.insert("func(a, b)", r#""is function 2""#, None)?;
1530 aliases_map.insert("func(a)", r#""is function a""#, None)?;
1531 aliases_map.insert("func(b)", r#""is function b""#, None)?;
1532
1533 let (id, params, defn, _doc) = aliases_map.get_function("func", 0).unwrap();
1534 assert_eq!(id, AliasId::Function("func", &[]));
1535 assert!(params.is_empty());
1536 assert_eq!(defn, r#""is function 0""#);
1537
1538 let (id, params, defn, _doc) = aliases_map.get_function("func", 1).unwrap();
1539 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1540 assert_eq!(params, ["b"]);
1541 assert_eq!(defn, r#""is function b""#);
1542
1543 let (id, params, defn, _doc) = aliases_map.get_function("func", 2).unwrap();
1544 assert_eq!(
1545 id,
1546 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1547 );
1548 assert_eq!(params, ["a", "b"]);
1549 assert_eq!(defn, r#""is function 2""#);
1550
1551 assert!(aliases_map.get_function("func", 3).is_none());
1552 Ok(())
1553 }
1554
1555 #[test]
1556 fn test_parse_revset_alias_formal_parameter() {
1557 let mut aliases_map = RevsetAliasesMap::new();
1558 assert!(aliases_map.insert("f(@)", "none()", None).is_err());
1560 assert!(aliases_map.insert("f(a@)", "none()", None).is_err());
1561 assert!(aliases_map.insert("f(a@b)", "none()", None).is_err());
1562 assert!(aliases_map.insert("f(,)", "none()", None).is_err());
1564 assert!(aliases_map.insert("g(a,)", "none()", None).is_ok());
1566 assert!(aliases_map.insert("h(a , )", "none()", None).is_ok());
1567 assert!(aliases_map.insert("i(,a)", "none()", None).is_err());
1568 assert!(aliases_map.insert("j(a,,)", "none()", None).is_err());
1569 assert!(aliases_map.insert("k(a , , )", "none()", None).is_err());
1570 assert!(aliases_map.insert("l(a,b,)", "none()", None).is_ok());
1571 assert!(aliases_map.insert("m(a,,b)", "none()", None).is_err());
1572 }
1573
1574 #[test]
1575 fn test_parse_revset_compat_operator() {
1576 assert_eq!(
1577 parse_into_kind(":foo"),
1578 Err(RevsetParseErrorKind::NotPrefixOperator {
1579 op: ":".to_owned(),
1580 similar_op: "::".to_owned(),
1581 description: "ancestors".to_owned(),
1582 })
1583 );
1584 assert_eq!(
1585 parse_into_kind("foo^"),
1586 Err(RevsetParseErrorKind::NotPostfixOperator {
1587 op: "^".to_owned(),
1588 similar_op: "-".to_owned(),
1589 description: "parents".to_owned(),
1590 })
1591 );
1592 assert_eq!(
1593 parse_into_kind("foo + bar"),
1594 Err(RevsetParseErrorKind::NotInfixOperator {
1595 op: "+".to_owned(),
1596 similar_op: "|".to_owned(),
1597 description: "union".to_owned(),
1598 })
1599 );
1600 assert_eq!(
1601 parse_into_kind("foo - bar"),
1602 Err(RevsetParseErrorKind::NotInfixOperator {
1603 op: "-".to_owned(),
1604 similar_op: "~".to_owned(),
1605 description: "difference".to_owned(),
1606 })
1607 );
1608 }
1609
1610 #[test]
1611 fn test_parse_deeply_nested_parentheses() {
1612 let depth = 32;
1617 let text = format!("{}root(){}", "(".repeat(depth), ")".repeat(depth));
1618 assert_eq!(parse_normalized(&text), parse_normalized("root()"));
1619 }
1620
1621 #[test]
1622 fn test_parse_revset_operator_combinations() {
1623 assert_eq!(parse_normalized("foo---"), parse_normalized("((foo-)-)-"));
1625 assert_eq!(parse_normalized("foo+++"), parse_normalized("((foo+)+)+"));
1627 assert_eq!(parse_normalized("~x|y"), parse_normalized("(~x)|y"));
1629 assert_eq!(parse_normalized("x&~y"), parse_normalized("x&(~y)"));
1630 assert_eq!(parse_normalized("x~~y"), parse_normalized("x~(~y)"));
1631 assert_eq!(parse_normalized("x~~~y"), parse_normalized("x~(~(~y))"));
1632 assert_eq!(parse_normalized("~x::y"), parse_normalized("~(x::y)"));
1633 assert_eq!(parse_normalized("x|y|z"), parse_normalized("(x|y)|z"));
1634 assert_eq!(parse_normalized("x&y|z"), parse_normalized("(x&y)|z"));
1635 assert_eq!(parse_normalized("x|y&z"), parse_normalized("x|(y&z)"));
1636 assert_eq!(parse_normalized("x|y~z"), parse_normalized("x|(y~z)"));
1637 assert_eq!(parse_normalized("::&.."), parse_normalized("(::)&(..)"));
1638 assert_eq!(
1640 parse_into_kind("::foo::"),
1641 Err(RevsetParseErrorKind::SyntaxError)
1642 );
1643 assert_eq!(
1644 parse_into_kind(":::foo"),
1645 Err(RevsetParseErrorKind::SyntaxError)
1646 );
1647 assert_eq!(
1648 parse_into_kind("::::foo"),
1649 Err(RevsetParseErrorKind::SyntaxError)
1650 );
1651 assert_eq!(
1652 parse_into_kind("foo:::"),
1653 Err(RevsetParseErrorKind::SyntaxError)
1654 );
1655 assert_eq!(
1656 parse_into_kind("foo::::"),
1657 Err(RevsetParseErrorKind::SyntaxError)
1658 );
1659 assert_eq!(
1660 parse_into_kind("foo:::bar"),
1661 Err(RevsetParseErrorKind::SyntaxError)
1662 );
1663 assert_eq!(
1664 parse_into_kind("foo::::bar"),
1665 Err(RevsetParseErrorKind::SyntaxError)
1666 );
1667 assert_eq!(
1668 parse_into_kind("::foo::bar"),
1669 Err(RevsetParseErrorKind::SyntaxError)
1670 );
1671 assert_eq!(
1672 parse_into_kind("foo::bar::"),
1673 Err(RevsetParseErrorKind::SyntaxError)
1674 );
1675 assert_eq!(
1676 parse_into_kind("::::"),
1677 Err(RevsetParseErrorKind::SyntaxError)
1678 );
1679 assert_eq!(
1680 parse_into_kind("....foo"),
1681 Err(RevsetParseErrorKind::SyntaxError)
1682 );
1683 assert_eq!(
1684 parse_into_kind("foo...."),
1685 Err(RevsetParseErrorKind::SyntaxError)
1686 );
1687 assert_eq!(
1688 parse_into_kind("foo.....bar"),
1689 Err(RevsetParseErrorKind::SyntaxError)
1690 );
1691 assert_eq!(
1692 parse_into_kind("..foo..bar"),
1693 Err(RevsetParseErrorKind::SyntaxError)
1694 );
1695 assert_eq!(
1696 parse_into_kind("foo..bar.."),
1697 Err(RevsetParseErrorKind::SyntaxError)
1698 );
1699 assert_eq!(
1700 parse_into_kind("...."),
1701 Err(RevsetParseErrorKind::SyntaxError)
1702 );
1703 assert_eq!(
1704 parse_into_kind("::.."),
1705 Err(RevsetParseErrorKind::SyntaxError)
1706 );
1707 assert_eq!(parse_normalized("foo-+"), parse_normalized("(foo-)+"));
1710 assert_eq!(parse_normalized("foo-::"), parse_normalized("(foo-)::"));
1711 assert_eq!(parse_normalized("::foo+"), parse_normalized("::(foo+)"));
1712 assert_eq!(
1713 parse_into_kind("::-"),
1714 Err(RevsetParseErrorKind::SyntaxError)
1715 );
1716 assert_eq!(
1717 parse_into_kind("..+"),
1718 Err(RevsetParseErrorKind::SyntaxError)
1719 );
1720 }
1721
1722 #[test]
1723 fn test_parse_revset_function() {
1724 assert_matches!(
1725 parse_into_kind("parents(foo)"),
1726 Ok(ExpressionKind::FunctionCall(_))
1727 );
1728 assert_eq!(
1729 parse_normalized("parents((foo))"),
1730 parse_normalized("parents(foo)"),
1731 );
1732 assert_eq!(
1733 parse_into_kind("parents(foo"),
1734 Err(RevsetParseErrorKind::SyntaxError)
1735 );
1736 }
1737
1738 #[test]
1739 fn test_expand_symbol_alias() {
1740 assert_eq!(
1741 with_aliases([("AB", "a&b")]).parse_normalized("AB|c"),
1742 parse_normalized("(a&b)|c")
1743 );
1744 assert_eq!(
1745 with_aliases([("AB", "a|b")]).parse_normalized("AB::heads(AB)"),
1746 parse_normalized("(a|b)::heads(a|b)")
1747 );
1748
1749 assert_eq!(
1751 with_aliases([("BC", "b|c")]).parse_normalized("a&BC"),
1752 parse_normalized("a&(b|c)")
1753 );
1754
1755 assert_eq!(
1757 with_aliases([("A", "a")]).parse_normalized(r#"A|"A"|'A'"#),
1758 parse_normalized("a|'A'|'A'")
1759 );
1760
1761 assert_eq!(
1764 with_aliases([("A", "a")]).parse_normalized("author(A:b)"),
1765 parse_normalized("author(A:b)")
1766 );
1767
1768 assert_eq!(
1770 with_aliases([("A", "a")]).parse_normalized("author(exact:A)"),
1771 parse_normalized("author(exact:a)")
1772 );
1773 assert_eq!(
1774 with_aliases([("A", "a")]).parse_normalized("author(exact:'A')"),
1775 parse_normalized("author(exact:'A')")
1776 );
1777
1778 assert_eq!(
1780 with_aliases([("A", "a")]).parse_normalized("A@"),
1781 parse_normalized("A@")
1782 );
1783 assert_eq!(
1784 with_aliases([("A", "a")]).parse_normalized("A@b"),
1785 parse_normalized("A@b")
1786 );
1787 assert_eq!(
1788 with_aliases([("B", "b")]).parse_normalized("a@B"),
1789 parse_normalized("a@B")
1790 );
1791
1792 assert_eq!(
1794 with_aliases([("A", "BC"), ("BC", "b|C"), ("C", "c")]).parse_normalized("A"),
1795 parse_normalized("b|c")
1796 );
1797
1798 assert_eq!(
1800 *with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1801 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1802 );
1803 assert_eq!(
1804 *with_aliases([("A", "B"), ("B", "b|C"), ("C", "c|B")])
1805 .parse("A")
1806 .unwrap_err()
1807 .kind,
1808 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1809 );
1810
1811 assert_eq!(
1813 *with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1814 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1815 );
1816 }
1817
1818 #[test]
1819 fn test_expand_pattern_alias() {
1820 assert_eq!(
1821 with_aliases([("P:x", "x")]).parse_normalized("P:a"),
1822 parse_normalized("a")
1823 );
1824
1825 assert_eq!(
1827 with_aliases([("P:x", "x|a")]).parse_normalized("P:x"),
1828 parse_normalized("x|a")
1829 );
1830 assert_eq!(
1832 with_aliases([("P:x", "(Q:x)&y"), ("Q:y", "x|y")]).parse_normalized("P:a"),
1833 parse_normalized("(x|a)&y")
1834 );
1835
1836 assert_eq!(
1838 with_aliases([("P:X", "X"), ("X", "x")]).parse_normalized("(P:a)|X"),
1839 parse_normalized("a|x")
1840 );
1841
1842 assert_eq!(
1844 with_aliases([("P:x", "x|A"), ("A", "x")]).parse_normalized("P:a"),
1845 parse_normalized("a|x")
1846 );
1847
1848 assert_eq!(
1850 with_aliases([("P:x", "x|'x'")]).parse_normalized("P:a"),
1851 parse_normalized("a|'x'")
1852 );
1853
1854 assert_eq!(
1856 with_aliases([("A:x", "A"), ("A", "a")]).parse_normalized("A:x"),
1857 parse_normalized("a")
1858 );
1859
1860 assert_eq!(
1862 *with_aliases([("P:x", "Q:x"), ("Q:x", "R:x"), ("R:x", "P:x")])
1863 .parse("P:a")
1864 .unwrap_err()
1865 .kind,
1866 RevsetParseErrorKind::InAliasExpansion("P:x".to_owned())
1867 );
1868 }
1869
1870 #[test]
1871 fn test_expand_function_alias() {
1872 assert_eq!(
1873 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1874 parse_normalized("a")
1875 );
1876 assert_eq!(
1877 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1878 parse_normalized("a")
1879 );
1880 assert_eq!(
1881 with_aliases([("F( x, y )", "x|y")]).parse_normalized("F(a, b)"),
1882 parse_normalized("a|b")
1883 );
1884
1885 assert_eq!(
1887 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x|y")]).parse_normalized("F(a)"),
1888 parse_normalized("a|b")
1889 );
1890
1891 assert_eq!(
1893 with_aliases([("F(x,y)", "x|y")]).parse_normalized("F(a::y,b::x)"),
1894 parse_normalized("(a::y)|(b::x)")
1895 );
1896 assert_eq!(
1898 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(a)"),
1899 parse_normalized("(x|a)&y")
1900 );
1901 assert_eq!(
1903 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(G(a))"),
1904 parse_normalized("(x|(x|a))&y")
1905 );
1906
1907 assert_eq!(
1909 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a)|X"),
1910 parse_normalized("a|x")
1911 );
1912
1913 assert_eq!(
1915 with_aliases([("F(x)", "x|A"), ("A", "x")]).parse_normalized("F(a)"),
1916 parse_normalized("a|x")
1917 );
1918
1919 assert_eq!(
1921 with_aliases([("F(x)", r#"x|"x""#)]).parse_normalized("F(a)"),
1922 parse_normalized("a|'x'")
1923 );
1924
1925 assert_eq!(
1927 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1928 parse_normalized("a")
1929 );
1930
1931 assert_eq!(
1933 *with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1934 RevsetParseErrorKind::InvalidFunctionArguments {
1935 name: "F".to_owned(),
1936 message: "Expected 0 arguments".to_owned()
1937 }
1938 );
1939 assert_eq!(
1940 *with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1941 RevsetParseErrorKind::InvalidFunctionArguments {
1942 name: "F".to_owned(),
1943 message: "Expected 1 arguments".to_owned()
1944 }
1945 );
1946 assert_eq!(
1947 *with_aliases([("F(x,y)", "x|y")])
1948 .parse("F(a,b,c)")
1949 .unwrap_err()
1950 .kind,
1951 RevsetParseErrorKind::InvalidFunctionArguments {
1952 name: "F".to_owned(),
1953 message: "Expected 2 arguments".to_owned()
1954 }
1955 );
1956 assert_eq!(
1957 *with_aliases([("F(x)", "x"), ("F(x,y)", "x|y")])
1958 .parse("F()")
1959 .unwrap_err()
1960 .kind,
1961 RevsetParseErrorKind::InvalidFunctionArguments {
1962 name: "F".to_owned(),
1963 message: "Expected 1 to 2 arguments".to_owned()
1964 }
1965 );
1966 assert_eq!(
1967 *with_aliases([("F()", "x"), ("F(x,y)", "x|y")])
1968 .parse("F(a)")
1969 .unwrap_err()
1970 .kind,
1971 RevsetParseErrorKind::InvalidFunctionArguments {
1972 name: "F".to_owned(),
1973 message: "Expected 0, 2 arguments".to_owned()
1974 }
1975 );
1976
1977 assert_eq!(
1979 *with_aliases([("F(x)", "x")])
1980 .parse("F(x=y)")
1981 .unwrap_err()
1982 .kind,
1983 RevsetParseErrorKind::InvalidFunctionArguments {
1984 name: "F".to_owned(),
1985 message: "Unexpected keyword arguments".to_owned()
1986 }
1987 );
1988
1989 assert_eq!(
1991 *with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1992 .parse("F(a)")
1993 .unwrap_err()
1994 .kind,
1995 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1996 );
1997 assert_eq!(
1998 *with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1999 .parse("F(a)")
2000 .unwrap_err()
2001 .kind,
2002 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
2003 );
2004 }
2005
2006 #[test]
2007 fn test_expand_with_locals() {
2008 assert_eq!(
2010 with_aliases([("A", "symbol")])
2011 .set_local("A", "local")
2012 .parse_normalized("A"),
2013 parse_normalized("local")
2014 );
2015
2016 assert_eq!(
2018 with_aliases([("B", "A"), ("F(x)", "x&A")])
2019 .set_local("A", "a")
2020 .parse_normalized("A|B|F(A)"),
2021 parse_normalized("a|A|(a&A)")
2022 );
2023 }
2024
2025 #[test]
2026 fn test_escape_string_literal() {
2027 assert_eq!(format_symbol("foo"), "foo");
2029 assert_eq!(format_symbol("foo.bar"), "foo.bar");
2030
2031 assert_eq!(format_symbol("foo@bar"), r#""foo@bar""#);
2033 assert_eq!(format_symbol("foo bar"), r#""foo bar""#);
2034 assert_eq!(format_symbol(" foo "), r#"" foo ""#);
2035 assert_eq!(format_symbol("(foo)"), r#""(foo)""#);
2036 assert_eq!(format_symbol("all:foo"), r#""all:foo""#);
2037
2038 assert_eq!(format_symbol("foo\"bar"), r#""foo\"bar""#);
2040 assert_eq!(format_symbol("foo\\bar"), r#""foo\\bar""#);
2041 assert_eq!(format_symbol("foo\\\"bar"), r#""foo\\\"bar""#);
2042 assert_eq!(format_symbol("foo\nbar"), r#""foo\nbar""#);
2043
2044 assert_eq!(format_symbol("foo\"bar"), r#""foo\"bar""#);
2047 assert_eq!(format_symbol("foo\\bar"), r#""foo\\bar""#);
2048 assert_eq!(format_symbol("foo\\\"bar"), r#""foo\\\"bar""#);
2049 assert_eq!(format_symbol("foo \x01 bar"), r#""foo \x01 bar""#);
2050 }
2051
2052 #[test]
2053 fn test_escape_remote_symbol() {
2054 assert_eq!(format_remote_symbol("foo", "bar"), "foo@bar");
2055 assert_eq!(
2056 format_remote_symbol(" foo ", "bar:baz"),
2057 r#"" foo "@"bar:baz""#
2058 );
2059 }
2060}