just playing with tangled
1// Copyright 2021-2024 The Jujutsu Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![allow(missing_docs)]
16
17use std::collections::HashSet;
18use std::error;
19use std::mem;
20use std::str::FromStr;
21
22use itertools::Itertools as _;
23use once_cell::sync::Lazy;
24use pest::iterators::Pair;
25use pest::iterators::Pairs;
26use pest::pratt_parser::Assoc;
27use pest::pratt_parser::Op;
28use pest::pratt_parser::PrattParser;
29use pest::Parser;
30use pest_derive::Parser;
31use thiserror::Error;
32
33use crate::dsl_util;
34use crate::dsl_util::collect_similar;
35use crate::dsl_util::AliasDeclaration;
36use crate::dsl_util::AliasDeclarationParser;
37use crate::dsl_util::AliasDefinitionParser;
38use crate::dsl_util::AliasExpandError;
39use crate::dsl_util::AliasExpandableExpression;
40use crate::dsl_util::AliasId;
41use crate::dsl_util::AliasesMap;
42use crate::dsl_util::Diagnostics;
43use crate::dsl_util::ExpressionFolder;
44use crate::dsl_util::FoldableExpression;
45use crate::dsl_util::FunctionCallParser;
46use crate::dsl_util::InvalidArguments;
47use crate::dsl_util::StringLiteralParser;
48
49#[derive(Parser)]
50#[grammar = "revset.pest"]
51struct RevsetParser;
52
53const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser {
54 content_rule: Rule::string_content,
55 escape_rule: Rule::string_escape,
56};
57const FUNCTION_CALL_PARSER: FunctionCallParser<Rule> = FunctionCallParser {
58 function_name_rule: Rule::function_name,
59 function_arguments_rule: Rule::function_arguments,
60 keyword_argument_rule: Rule::keyword_argument,
61 argument_name_rule: Rule::strict_identifier,
62 argument_value_rule: Rule::expression,
63};
64
65impl Rule {
66 /// Whether this is a placeholder rule for compatibility with the other
67 /// systems.
68 fn is_compat(&self) -> bool {
69 matches!(
70 self,
71 Rule::compat_parents_op
72 | Rule::compat_dag_range_op
73 | Rule::compat_dag_range_pre_op
74 | Rule::compat_dag_range_post_op
75 | Rule::compat_add_op
76 | Rule::compat_sub_op
77 )
78 }
79
80 fn to_symbol(self) -> Option<&'static str> {
81 match self {
82 Rule::EOI => None,
83 Rule::whitespace => None,
84 Rule::identifier_part => None,
85 Rule::identifier => None,
86 Rule::strict_identifier_part => None,
87 Rule::strict_identifier => None,
88 Rule::symbol => None,
89 Rule::string_escape => None,
90 Rule::string_content_char => None,
91 Rule::string_content => None,
92 Rule::string_literal => None,
93 Rule::raw_string_content => None,
94 Rule::raw_string_literal => None,
95 Rule::at_op => Some("@"),
96 Rule::pattern_kind_op => Some(":"),
97 Rule::parents_op => Some("-"),
98 Rule::children_op => Some("+"),
99 Rule::compat_parents_op => Some("^"),
100 Rule::dag_range_op
101 | Rule::dag_range_pre_op
102 | Rule::dag_range_post_op
103 | Rule::dag_range_all_op => Some("::"),
104 Rule::compat_dag_range_op
105 | Rule::compat_dag_range_pre_op
106 | Rule::compat_dag_range_post_op => Some(":"),
107 Rule::range_op => Some(".."),
108 Rule::range_pre_op | Rule::range_post_op | Rule::range_all_op => Some(".."),
109 Rule::range_ops => None,
110 Rule::range_pre_ops => None,
111 Rule::range_post_ops => None,
112 Rule::range_all_ops => None,
113 Rule::negate_op => Some("~"),
114 Rule::union_op => Some("|"),
115 Rule::intersection_op => Some("&"),
116 Rule::difference_op => Some("~"),
117 Rule::compat_add_op => Some("+"),
118 Rule::compat_sub_op => Some("-"),
119 Rule::infix_op => None,
120 Rule::function => None,
121 Rule::function_name => None,
122 Rule::keyword_argument => None,
123 Rule::argument => None,
124 Rule::function_arguments => None,
125 Rule::formal_parameters => None,
126 Rule::string_pattern => None,
127 Rule::primary => None,
128 Rule::neighbors_expression => None,
129 Rule::range_expression => None,
130 Rule::expression => None,
131 Rule::program_modifier => None,
132 Rule::program => None,
133 Rule::function_alias_declaration => None,
134 Rule::alias_declaration => None,
135 }
136 }
137}
138
139/// Manages diagnostic messages emitted during revset parsing and function-call
140/// resolution.
141pub type RevsetDiagnostics = Diagnostics<RevsetParseError>;
142
143#[derive(Debug, Error)]
144#[error("{pest_error}")]
145pub struct RevsetParseError {
146 kind: RevsetParseErrorKind,
147 pest_error: Box<pest::error::Error<Rule>>,
148 source: Option<Box<dyn error::Error + Send + Sync>>,
149}
150
151#[derive(Debug, Error, PartialEq, Eq)]
152pub enum RevsetParseErrorKind {
153 #[error("Syntax error")]
154 SyntaxError,
155 #[error("`{op}` is not a prefix operator")]
156 NotPrefixOperator {
157 op: String,
158 similar_op: String,
159 description: String,
160 },
161 #[error("`{op}` is not a postfix operator")]
162 NotPostfixOperator {
163 op: String,
164 similar_op: String,
165 description: String,
166 },
167 #[error("`{op}` is not an infix operator")]
168 NotInfixOperator {
169 op: String,
170 similar_op: String,
171 description: String,
172 },
173 #[error("Modifier `{0}` doesn't exist")]
174 NoSuchModifier(String),
175 #[error("Function `{name}` doesn't exist")]
176 NoSuchFunction {
177 name: String,
178 candidates: Vec<String>,
179 },
180 #[error("Function `{name}`: {message}")]
181 InvalidFunctionArguments { name: String, message: String },
182 #[error("Cannot resolve file pattern without workspace")]
183 FsPathWithoutWorkspace,
184 #[error("Cannot resolve `@` without workspace")]
185 WorkingCopyWithoutWorkspace,
186 #[error("Redefinition of function parameter")]
187 RedefinedFunctionParameter,
188 #[error("{0}")]
189 Expression(String),
190 #[error("In alias `{0}`")]
191 InAliasExpansion(String),
192 #[error("In function parameter `{0}`")]
193 InParameterExpansion(String),
194 #[error("Alias `{0}` expanded recursively")]
195 RecursiveAlias(String),
196}
197
198impl RevsetParseError {
199 pub(super) fn with_span(kind: RevsetParseErrorKind, span: pest::Span<'_>) -> Self {
200 let message = kind.to_string();
201 let pest_error = Box::new(pest::error::Error::new_from_span(
202 pest::error::ErrorVariant::CustomError { message },
203 span,
204 ));
205 RevsetParseError {
206 kind,
207 pest_error,
208 source: None,
209 }
210 }
211
212 pub(super) fn with_source(
213 mut self,
214 source: impl Into<Box<dyn error::Error + Send + Sync>>,
215 ) -> Self {
216 self.source = Some(source.into());
217 self
218 }
219
220 /// Some other expression error.
221 pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {
222 Self::with_span(RevsetParseErrorKind::Expression(message.into()), span)
223 }
224
225 /// If this is a `NoSuchFunction` error, expands the candidates list with
226 /// the given `other_functions`.
227 pub(super) fn extend_function_candidates<I>(mut self, other_functions: I) -> Self
228 where
229 I: IntoIterator,
230 I::Item: AsRef<str>,
231 {
232 if let RevsetParseErrorKind::NoSuchFunction { name, candidates } = &mut self.kind {
233 let other_candidates = collect_similar(name, other_functions);
234 *candidates = itertools::merge(mem::take(candidates), other_candidates)
235 .dedup()
236 .collect();
237 }
238 self
239 }
240
241 pub fn kind(&self) -> &RevsetParseErrorKind {
242 &self.kind
243 }
244
245 /// Original parsing error which typically occurred in an alias expression.
246 pub fn origin(&self) -> Option<&Self> {
247 self.source.as_ref().and_then(|e| e.downcast_ref())
248 }
249}
250
251impl AliasExpandError for RevsetParseError {
252 fn invalid_arguments(err: InvalidArguments<'_>) -> Self {
253 err.into()
254 }
255
256 fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self {
257 Self::with_span(RevsetParseErrorKind::RecursiveAlias(id.to_string()), span)
258 }
259
260 fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {
261 let kind = match id {
262 AliasId::Symbol(_) | AliasId::Function(..) => {
263 RevsetParseErrorKind::InAliasExpansion(id.to_string())
264 }
265 AliasId::Parameter(_) => RevsetParseErrorKind::InParameterExpansion(id.to_string()),
266 };
267 Self::with_span(kind, span).with_source(self)
268 }
269}
270
271impl From<pest::error::Error<Rule>> for RevsetParseError {
272 fn from(err: pest::error::Error<Rule>) -> Self {
273 RevsetParseError {
274 kind: RevsetParseErrorKind::SyntaxError,
275 pest_error: Box::new(rename_rules_in_pest_error(err)),
276 source: None,
277 }
278 }
279}
280
281impl From<InvalidArguments<'_>> for RevsetParseError {
282 fn from(err: InvalidArguments<'_>) -> Self {
283 let kind = RevsetParseErrorKind::InvalidFunctionArguments {
284 name: err.name.to_owned(),
285 message: err.message,
286 };
287 Self::with_span(kind, err.span)
288 }
289}
290
291fn rename_rules_in_pest_error(mut err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {
292 let pest::error::ErrorVariant::ParsingError {
293 positives,
294 negatives,
295 } = &mut err.variant
296 else {
297 return err;
298 };
299
300 // Remove duplicated symbols. Compat symbols are also removed from the
301 // (positive) suggestion.
302 let mut known_syms = HashSet::new();
303 positives.retain(|rule| {
304 !rule.is_compat() && rule.to_symbol().map_or(true, |sym| known_syms.insert(sym))
305 });
306 let mut known_syms = HashSet::new();
307 negatives.retain(|rule| rule.to_symbol().map_or(true, |sym| known_syms.insert(sym)));
308 err.renamed_rules(|rule| {
309 rule.to_symbol()
310 .map(|sym| format!("`{sym}`"))
311 .unwrap_or_else(|| format!("<{rule:?}>"))
312 })
313}
314
315#[derive(Clone, Debug, Eq, PartialEq)]
316pub enum ExpressionKind<'i> {
317 /// Unquoted symbol.
318 Identifier(&'i str),
319 /// Quoted symbol or string.
320 String(String),
321 /// `<kind>:<value>`
322 StringPattern {
323 kind: &'i str,
324 value: String,
325 },
326 /// `<name>@<remote>`
327 RemoteSymbol {
328 name: String,
329 remote: String,
330 },
331 /// `<workspace_id>@`
332 AtWorkspace(String),
333 /// `@`
334 AtCurrentWorkspace,
335 /// `::`
336 DagRangeAll,
337 /// `..`
338 RangeAll,
339 Unary(UnaryOp, Box<ExpressionNode<'i>>),
340 Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),
341 /// `x | y | ..`
342 UnionAll(Vec<ExpressionNode<'i>>),
343 FunctionCall(Box<FunctionCallNode<'i>>),
344 /// `name: body`
345 Modifier(Box<ModifierNode<'i>>),
346 /// Identity node to preserve the span in the source text.
347 AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),
348}
349
350impl<'i> FoldableExpression<'i> for ExpressionKind<'i> {
351 fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>
352 where
353 F: ExpressionFolder<'i, Self> + ?Sized,
354 {
355 match self {
356 ExpressionKind::Identifier(name) => folder.fold_identifier(name, span),
357 ExpressionKind::String(_)
358 | ExpressionKind::StringPattern { .. }
359 | ExpressionKind::RemoteSymbol { .. }
360 | ExpressionKind::AtWorkspace(_)
361 | ExpressionKind::AtCurrentWorkspace
362 | ExpressionKind::DagRangeAll
363 | ExpressionKind::RangeAll => Ok(self),
364 ExpressionKind::Unary(op, arg) => {
365 let arg = Box::new(folder.fold_expression(*arg)?);
366 Ok(ExpressionKind::Unary(op, arg))
367 }
368 ExpressionKind::Binary(op, lhs, rhs) => {
369 let lhs = Box::new(folder.fold_expression(*lhs)?);
370 let rhs = Box::new(folder.fold_expression(*rhs)?);
371 Ok(ExpressionKind::Binary(op, lhs, rhs))
372 }
373 ExpressionKind::UnionAll(nodes) => {
374 let nodes = dsl_util::fold_expression_nodes(folder, nodes)?;
375 Ok(ExpressionKind::UnionAll(nodes))
376 }
377 ExpressionKind::FunctionCall(function) => folder.fold_function_call(function, span),
378 ExpressionKind::Modifier(modifier) => {
379 let modifier = Box::new(ModifierNode {
380 name: modifier.name,
381 name_span: modifier.name_span,
382 body: folder.fold_expression(modifier.body)?,
383 });
384 Ok(ExpressionKind::Modifier(modifier))
385 }
386 ExpressionKind::AliasExpanded(id, subst) => {
387 let subst = Box::new(folder.fold_expression(*subst)?);
388 Ok(ExpressionKind::AliasExpanded(id, subst))
389 }
390 }
391 }
392}
393
394impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {
395 fn identifier(name: &'i str) -> Self {
396 ExpressionKind::Identifier(name)
397 }
398
399 fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {
400 ExpressionKind::FunctionCall(function)
401 }
402
403 fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {
404 ExpressionKind::AliasExpanded(id, subst)
405 }
406}
407
408#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
409pub enum UnaryOp {
410 /// `~x`
411 Negate,
412 /// `::x`
413 DagRangePre,
414 /// `x::`
415 DagRangePost,
416 /// `..x`
417 RangePre,
418 /// `x..`
419 RangePost,
420 /// `x-`
421 Parents,
422 /// `x+`
423 Children,
424}
425
426#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
427pub enum BinaryOp {
428 /// `&`
429 Intersection,
430 /// `~`
431 Difference,
432 /// `::`
433 DagRange,
434 /// `..`
435 Range,
436}
437
438pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>;
439pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>;
440
441/// Expression with modifier `name: body`.
442#[derive(Clone, Debug, Eq, PartialEq)]
443pub struct ModifierNode<'i> {
444 /// Modifier name.
445 pub name: &'i str,
446 /// Span of the modifier name.
447 pub name_span: pest::Span<'i>,
448 /// Expression body.
449 pub body: ExpressionNode<'i>,
450}
451
452fn union_nodes<'i>(lhs: ExpressionNode<'i>, rhs: ExpressionNode<'i>) -> ExpressionNode<'i> {
453 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
454 let expr = match lhs.kind {
455 // Flatten "x | y | z" to save recursion stack. Machine-generated query
456 // might have long chain of unions.
457 ExpressionKind::UnionAll(mut nodes) => {
458 nodes.push(rhs);
459 ExpressionKind::UnionAll(nodes)
460 }
461 _ => ExpressionKind::UnionAll(vec![lhs, rhs]),
462 };
463 ExpressionNode::new(expr, span)
464}
465
466pub(super) fn parse_program(revset_str: &str) -> Result<ExpressionNode, RevsetParseError> {
467 let mut pairs = RevsetParser::parse(Rule::program, revset_str)?;
468 let first = pairs.next().unwrap();
469 match first.as_rule() {
470 Rule::expression => parse_expression_node(first.into_inner()),
471 Rule::program_modifier => {
472 let (lhs, op) = first.into_inner().collect_tuple().unwrap();
473 let rhs = pairs.next().unwrap();
474 assert_eq!(lhs.as_rule(), Rule::strict_identifier);
475 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
476 assert_eq!(rhs.as_rule(), Rule::expression);
477 let span = lhs.as_span().start_pos().span(&rhs.as_span().end_pos());
478 let modifier = Box::new(ModifierNode {
479 name: lhs.as_str(),
480 name_span: lhs.as_span(),
481 body: parse_expression_node(rhs.into_inner())?,
482 });
483 let expr = ExpressionKind::Modifier(modifier);
484 Ok(ExpressionNode::new(expr, span))
485 }
486 r => panic!("unexpected revset parse rule: {r:?}"),
487 }
488}
489
490fn parse_expression_node(pairs: Pairs<Rule>) -> Result<ExpressionNode, RevsetParseError> {
491 fn not_prefix_op(
492 op: &Pair<Rule>,
493 similar_op: impl Into<String>,
494 description: impl Into<String>,
495 ) -> RevsetParseError {
496 RevsetParseError::with_span(
497 RevsetParseErrorKind::NotPrefixOperator {
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_postfix_op(
507 op: &Pair<Rule>,
508 similar_op: impl Into<String>,
509 description: impl Into<String>,
510 ) -> RevsetParseError {
511 RevsetParseError::with_span(
512 RevsetParseErrorKind::NotPostfixOperator {
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 fn not_infix_op(
522 op: &Pair<Rule>,
523 similar_op: impl Into<String>,
524 description: impl Into<String>,
525 ) -> RevsetParseError {
526 RevsetParseError::with_span(
527 RevsetParseErrorKind::NotInfixOperator {
528 op: op.as_str().to_owned(),
529 similar_op: similar_op.into(),
530 description: description.into(),
531 },
532 op.as_span(),
533 )
534 }
535
536 static PRATT: Lazy<PrattParser<Rule>> = Lazy::new(|| {
537 PrattParser::new()
538 .op(Op::infix(Rule::union_op, Assoc::Left)
539 | Op::infix(Rule::compat_add_op, Assoc::Left))
540 .op(Op::infix(Rule::intersection_op, Assoc::Left)
541 | Op::infix(Rule::difference_op, Assoc::Left)
542 | Op::infix(Rule::compat_sub_op, Assoc::Left))
543 .op(Op::prefix(Rule::negate_op))
544 // Ranges can't be nested without parentheses. Associativity doesn't matter.
545 .op(Op::infix(Rule::dag_range_op, Assoc::Left)
546 | Op::infix(Rule::compat_dag_range_op, Assoc::Left)
547 | Op::infix(Rule::range_op, Assoc::Left))
548 .op(Op::prefix(Rule::dag_range_pre_op)
549 | Op::prefix(Rule::compat_dag_range_pre_op)
550 | Op::prefix(Rule::range_pre_op))
551 .op(Op::postfix(Rule::dag_range_post_op)
552 | Op::postfix(Rule::compat_dag_range_post_op)
553 | Op::postfix(Rule::range_post_op))
554 // Neighbors
555 .op(Op::postfix(Rule::parents_op)
556 | Op::postfix(Rule::children_op)
557 | Op::postfix(Rule::compat_parents_op))
558 });
559 PRATT
560 .map_primary(|primary| {
561 let expr = match primary.as_rule() {
562 Rule::primary => return parse_primary_node(primary),
563 Rule::dag_range_all_op => ExpressionKind::DagRangeAll,
564 Rule::range_all_op => ExpressionKind::RangeAll,
565 r => panic!("unexpected primary rule {r:?}"),
566 };
567 Ok(ExpressionNode::new(expr, primary.as_span()))
568 })
569 .map_prefix(|op, rhs| {
570 let op_kind = match op.as_rule() {
571 Rule::negate_op => UnaryOp::Negate,
572 Rule::dag_range_pre_op => UnaryOp::DagRangePre,
573 Rule::compat_dag_range_pre_op => Err(not_prefix_op(&op, "::", "ancestors"))?,
574 Rule::range_pre_op => UnaryOp::RangePre,
575 r => panic!("unexpected prefix operator rule {r:?}"),
576 };
577 let rhs = Box::new(rhs?);
578 let span = op.as_span().start_pos().span(&rhs.span.end_pos());
579 let expr = ExpressionKind::Unary(op_kind, rhs);
580 Ok(ExpressionNode::new(expr, span))
581 })
582 .map_postfix(|lhs, op| {
583 let op_kind = match op.as_rule() {
584 Rule::dag_range_post_op => UnaryOp::DagRangePost,
585 Rule::compat_dag_range_post_op => Err(not_postfix_op(&op, "::", "descendants"))?,
586 Rule::range_post_op => UnaryOp::RangePost,
587 Rule::parents_op => UnaryOp::Parents,
588 Rule::children_op => UnaryOp::Children,
589 Rule::compat_parents_op => Err(not_postfix_op(&op, "-", "parents"))?,
590 r => panic!("unexpected postfix operator rule {r:?}"),
591 };
592 let lhs = Box::new(lhs?);
593 let span = lhs.span.start_pos().span(&op.as_span().end_pos());
594 let expr = ExpressionKind::Unary(op_kind, lhs);
595 Ok(ExpressionNode::new(expr, span))
596 })
597 .map_infix(|lhs, op, rhs| {
598 let op_kind = match op.as_rule() {
599 Rule::union_op => return Ok(union_nodes(lhs?, rhs?)),
600 Rule::compat_add_op => Err(not_infix_op(&op, "|", "union"))?,
601 Rule::intersection_op => BinaryOp::Intersection,
602 Rule::difference_op => BinaryOp::Difference,
603 Rule::compat_sub_op => Err(not_infix_op(&op, "~", "difference"))?,
604 Rule::dag_range_op => BinaryOp::DagRange,
605 Rule::compat_dag_range_op => Err(not_infix_op(&op, "::", "DAG range"))?,
606 Rule::range_op => BinaryOp::Range,
607 r => panic!("unexpected infix operator rule {r:?}"),
608 };
609 let lhs = Box::new(lhs?);
610 let rhs = Box::new(rhs?);
611 let span = lhs.span.start_pos().span(&rhs.span.end_pos());
612 let expr = ExpressionKind::Binary(op_kind, lhs, rhs);
613 Ok(ExpressionNode::new(expr, span))
614 })
615 .parse(pairs)
616}
617
618fn parse_primary_node(pair: Pair<Rule>) -> Result<ExpressionNode, RevsetParseError> {
619 let span = pair.as_span();
620 let mut pairs = pair.into_inner();
621 let first = pairs.next().unwrap();
622 let expr = match first.as_rule() {
623 Rule::expression => return parse_expression_node(first.into_inner()),
624 Rule::function => {
625 let function = Box::new(FUNCTION_CALL_PARSER.parse(
626 first,
627 |pair| Ok(pair.as_str()),
628 |pair| parse_expression_node(pair.into_inner()),
629 )?);
630 ExpressionKind::FunctionCall(function)
631 }
632 Rule::string_pattern => {
633 let (lhs, op, rhs) = first.into_inner().collect_tuple().unwrap();
634 assert_eq!(lhs.as_rule(), Rule::strict_identifier);
635 assert_eq!(op.as_rule(), Rule::pattern_kind_op);
636 let kind = lhs.as_str();
637 let value = parse_as_string_literal(rhs);
638 ExpressionKind::StringPattern { kind, value }
639 }
640 // Identifier without "@" may be substituted by aliases. Primary expression including "@"
641 // is considered an indecomposable unit, and no alias substitution would be made.
642 Rule::identifier if pairs.peek().is_none() => ExpressionKind::Identifier(first.as_str()),
643 Rule::identifier | Rule::string_literal | Rule::raw_string_literal => {
644 let name = parse_as_string_literal(first);
645 match pairs.next() {
646 None => ExpressionKind::String(name),
647 Some(op) => {
648 assert_eq!(op.as_rule(), Rule::at_op);
649 match pairs.next() {
650 // postfix "<workspace_id>@"
651 None => ExpressionKind::AtWorkspace(name),
652 // infix "<name>@<remote>"
653 Some(second) => {
654 let remote = parse_as_string_literal(second);
655 ExpressionKind::RemoteSymbol { name, remote }
656 }
657 }
658 }
659 }
660 }
661 // nullary "@"
662 Rule::at_op => ExpressionKind::AtCurrentWorkspace,
663 r => panic!("unexpected revset parse rule: {r:?}"),
664 };
665 Ok(ExpressionNode::new(expr, span))
666}
667
668/// Parses part of compound symbol to string.
669fn parse_as_string_literal(pair: Pair<Rule>) -> String {
670 match pair.as_rule() {
671 Rule::identifier => pair.as_str().to_owned(),
672 Rule::string_literal => STRING_LITERAL_PARSER.parse(pair.into_inner()),
673 Rule::raw_string_literal => {
674 let (content,) = pair.into_inner().collect_tuple().unwrap();
675 assert_eq!(content.as_rule(), Rule::raw_string_content);
676 content.as_str().to_owned()
677 }
678 _ => {
679 panic!("unexpected string literal rule: {:?}", pair.as_str());
680 }
681 }
682}
683
684/// Checks if the text is a valid identifier
685pub fn is_identifier(text: &str) -> bool {
686 match RevsetParser::parse(Rule::identifier, text) {
687 Ok(mut pairs) => pairs.next().unwrap().as_span().end() == text.len(),
688 Err(_) => false,
689 }
690}
691
692pub type RevsetAliasesMap = AliasesMap<RevsetAliasParser, String>;
693
694#[derive(Clone, Debug, Default)]
695pub struct RevsetAliasParser;
696
697impl AliasDeclarationParser for RevsetAliasParser {
698 type Error = RevsetParseError;
699
700 fn parse_declaration(&self, source: &str) -> Result<AliasDeclaration, Self::Error> {
701 let mut pairs = RevsetParser::parse(Rule::alias_declaration, source)?;
702 let first = pairs.next().unwrap();
703 match first.as_rule() {
704 Rule::strict_identifier => Ok(AliasDeclaration::Symbol(first.as_str().to_owned())),
705 Rule::function_alias_declaration => {
706 let (name_pair, params_pair) = first.into_inner().collect_tuple().unwrap();
707 assert_eq!(name_pair.as_rule(), Rule::function_name);
708 assert_eq!(params_pair.as_rule(), Rule::formal_parameters);
709 let name = name_pair.as_str().to_owned();
710 let params_span = params_pair.as_span();
711 let params = params_pair
712 .into_inner()
713 .map(|pair| match pair.as_rule() {
714 Rule::strict_identifier => pair.as_str().to_owned(),
715 r => panic!("unexpected formal parameter rule {r:?}"),
716 })
717 .collect_vec();
718 if params.iter().all_unique() {
719 Ok(AliasDeclaration::Function(name, params))
720 } else {
721 Err(RevsetParseError::with_span(
722 RevsetParseErrorKind::RedefinedFunctionParameter,
723 params_span,
724 ))
725 }
726 }
727 r => panic!("unexpected alias declaration rule {r:?}"),
728 }
729 }
730}
731
732impl AliasDefinitionParser for RevsetAliasParser {
733 type Output<'i> = ExpressionKind<'i>;
734 type Error = RevsetParseError;
735
736 fn parse_definition<'i>(&self, source: &'i str) -> Result<ExpressionNode<'i>, Self::Error> {
737 parse_program(source)
738 }
739}
740
741/// Applies the given functions to the top-level expression body node with an
742/// optional modifier. Alias expansion nodes are unwrapped accordingly.
743pub(super) fn expect_program_with<B, M>(
744 diagnostics: &mut RevsetDiagnostics,
745 node: &ExpressionNode,
746 parse_body: impl FnOnce(&mut RevsetDiagnostics, &ExpressionNode) -> Result<B, RevsetParseError>,
747 parse_modifier: impl FnOnce(
748 &mut RevsetDiagnostics,
749 &str,
750 pest::Span<'_>,
751 ) -> Result<M, RevsetParseError>,
752) -> Result<(B, Option<M>), RevsetParseError> {
753 expect_expression_with(diagnostics, node, |diagnostics, node| match &node.kind {
754 ExpressionKind::Modifier(modifier) => {
755 let parsed_modifier = parse_modifier(diagnostics, modifier.name, modifier.name_span)?;
756 let parsed_body = parse_body(diagnostics, &modifier.body)?;
757 Ok((parsed_body, Some(parsed_modifier)))
758 }
759 _ => Ok((parse_body(diagnostics, node)?, None)),
760 })
761}
762
763pub(super) fn expect_pattern_with<T, E: Into<Box<dyn error::Error + Send + Sync>>>(
764 diagnostics: &mut RevsetDiagnostics,
765 type_name: &str,
766 node: &ExpressionNode,
767 parse_pattern: impl FnOnce(&mut RevsetDiagnostics, &str, Option<&str>) -> Result<T, E>,
768) -> Result<T, RevsetParseError> {
769 let wrap_error = |err: E| {
770 RevsetParseError::expression(format!("Invalid {type_name}"), node.span).with_source(err)
771 };
772 expect_expression_with(diagnostics, node, |diagnostics, node| match &node.kind {
773 ExpressionKind::Identifier(name) => {
774 parse_pattern(diagnostics, name, None).map_err(wrap_error)
775 }
776 ExpressionKind::String(name) => parse_pattern(diagnostics, name, None).map_err(wrap_error),
777 ExpressionKind::StringPattern { kind, value } => {
778 parse_pattern(diagnostics, value, Some(kind)).map_err(wrap_error)
779 }
780 _ => Err(RevsetParseError::expression(
781 format!("Expected expression of {type_name}"),
782 node.span,
783 )),
784 })
785}
786
787pub fn expect_literal<T: FromStr>(
788 diagnostics: &mut RevsetDiagnostics,
789 type_name: &str,
790 node: &ExpressionNode,
791) -> Result<T, RevsetParseError> {
792 let make_error = || {
793 RevsetParseError::expression(
794 format!("Expected expression of type {type_name}"),
795 node.span,
796 )
797 };
798 expect_expression_with(diagnostics, node, |_diagnostics, node| match &node.kind {
799 ExpressionKind::Identifier(name) => name.parse().map_err(|_| make_error()),
800 ExpressionKind::String(name) => name.parse().map_err(|_| make_error()),
801 _ => Err(make_error()),
802 })
803}
804
805/// Applies the give function to the innermost `node` by unwrapping alias
806/// expansion nodes.
807pub(super) fn expect_expression_with<T>(
808 diagnostics: &mut RevsetDiagnostics,
809 node: &ExpressionNode,
810 f: impl FnOnce(&mut RevsetDiagnostics, &ExpressionNode) -> Result<T, RevsetParseError>,
811) -> Result<T, RevsetParseError> {
812 if let ExpressionKind::AliasExpanded(id, subst) = &node.kind {
813 let mut inner_diagnostics = RevsetDiagnostics::new();
814 let expression = expect_expression_with(&mut inner_diagnostics, subst, f)
815 .map_err(|e| e.within_alias_expansion(*id, node.span))?;
816 diagnostics.extend_with(inner_diagnostics, |diag| {
817 diag.within_alias_expansion(*id, node.span)
818 });
819 Ok(expression)
820 } else {
821 f(diagnostics, node)
822 }
823}
824
825#[cfg(test)]
826mod tests {
827 use assert_matches::assert_matches;
828
829 use super::*;
830 use crate::dsl_util::KeywordArgument;
831
832 #[derive(Debug)]
833 struct WithRevsetAliasesMap(RevsetAliasesMap);
834
835 impl WithRevsetAliasesMap {
836 fn parse<'i>(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> {
837 let node = parse_program(text)?;
838 dsl_util::expand_aliases(node, &self.0)
839 }
840
841 fn parse_normalized<'i>(&'i self, text: &'i str) -> ExpressionNode<'i> {
842 normalize_tree(self.parse(text).unwrap())
843 }
844 }
845
846 fn with_aliases(
847 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>,
848 ) -> WithRevsetAliasesMap {
849 let mut aliases_map = RevsetAliasesMap::new();
850 for (decl, defn) in aliases {
851 aliases_map.insert(decl, defn).unwrap();
852 }
853 WithRevsetAliasesMap(aliases_map)
854 }
855
856 fn parse_into_kind(text: &str) -> Result<ExpressionKind, RevsetParseErrorKind> {
857 parse_program(text)
858 .map(|node| node.kind)
859 .map_err(|err| err.kind)
860 }
861
862 fn parse_normalized(text: &str) -> ExpressionNode {
863 normalize_tree(parse_program(text).unwrap())
864 }
865
866 /// Drops auxiliary data from parsed tree so it can be compared with other.
867 fn normalize_tree(node: ExpressionNode) -> ExpressionNode {
868 fn empty_span() -> pest::Span<'static> {
869 pest::Span::new("", 0, 0).unwrap()
870 }
871
872 fn normalize_list(nodes: Vec<ExpressionNode>) -> Vec<ExpressionNode> {
873 nodes.into_iter().map(normalize_tree).collect()
874 }
875
876 fn normalize_function_call(function: FunctionCallNode) -> FunctionCallNode {
877 FunctionCallNode {
878 name: function.name,
879 name_span: empty_span(),
880 args: normalize_list(function.args),
881 keyword_args: function
882 .keyword_args
883 .into_iter()
884 .map(|arg| KeywordArgument {
885 name: arg.name,
886 name_span: empty_span(),
887 value: normalize_tree(arg.value),
888 })
889 .collect(),
890 args_span: empty_span(),
891 }
892 }
893
894 let normalized_kind = match node.kind {
895 ExpressionKind::Identifier(_)
896 | ExpressionKind::String(_)
897 | ExpressionKind::StringPattern { .. }
898 | ExpressionKind::RemoteSymbol { .. }
899 | ExpressionKind::AtWorkspace(_)
900 | ExpressionKind::AtCurrentWorkspace
901 | ExpressionKind::DagRangeAll
902 | ExpressionKind::RangeAll => node.kind,
903 ExpressionKind::Unary(op, arg) => {
904 let arg = Box::new(normalize_tree(*arg));
905 ExpressionKind::Unary(op, arg)
906 }
907 ExpressionKind::Binary(op, lhs, rhs) => {
908 let lhs = Box::new(normalize_tree(*lhs));
909 let rhs = Box::new(normalize_tree(*rhs));
910 ExpressionKind::Binary(op, lhs, rhs)
911 }
912 ExpressionKind::UnionAll(nodes) => {
913 let nodes = normalize_list(nodes);
914 ExpressionKind::UnionAll(nodes)
915 }
916 ExpressionKind::FunctionCall(function) => {
917 let function = Box::new(normalize_function_call(*function));
918 ExpressionKind::FunctionCall(function)
919 }
920 ExpressionKind::Modifier(modifier) => {
921 let modifier = Box::new(ModifierNode {
922 name: modifier.name,
923 name_span: empty_span(),
924 body: normalize_tree(modifier.body),
925 });
926 ExpressionKind::Modifier(modifier)
927 }
928 ExpressionKind::AliasExpanded(_, subst) => normalize_tree(*subst).kind,
929 };
930 ExpressionNode {
931 kind: normalized_kind,
932 span: empty_span(),
933 }
934 }
935
936 #[test]
937 fn test_parse_tree_eq() {
938 assert_eq!(
939 parse_normalized(r#" foo( x ) | ~bar:"baz" "#),
940 parse_normalized(r#"(foo(x))|(~(bar:"baz"))"#)
941 );
942 assert_ne!(parse_normalized(r#" foo "#), parse_normalized(r#" "foo" "#));
943 }
944
945 #[test]
946 fn test_parse_revset() {
947 // Parse a quoted symbol
948 assert_eq!(
949 parse_into_kind("\"foo\""),
950 Ok(ExpressionKind::String("foo".to_owned()))
951 );
952 assert_eq!(
953 parse_into_kind("'foo'"),
954 Ok(ExpressionKind::String("foo".to_owned()))
955 );
956 // Parse the "parents" operator
957 assert_matches!(
958 parse_into_kind("foo-"),
959 Ok(ExpressionKind::Unary(UnaryOp::Parents, _))
960 );
961 // Parse the "children" operator
962 assert_matches!(
963 parse_into_kind("foo+"),
964 Ok(ExpressionKind::Unary(UnaryOp::Children, _))
965 );
966 // Parse the "ancestors" operator
967 assert_matches!(
968 parse_into_kind("::foo"),
969 Ok(ExpressionKind::Unary(UnaryOp::DagRangePre, _))
970 );
971 // Parse the "descendants" operator
972 assert_matches!(
973 parse_into_kind("foo::"),
974 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
975 );
976 // Parse the "dag range" operator
977 assert_matches!(
978 parse_into_kind("foo::bar"),
979 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
980 );
981 // Parse the nullary "dag range" operator
982 assert_matches!(parse_into_kind("::"), Ok(ExpressionKind::DagRangeAll));
983 // Parse the "range" prefix operator
984 assert_matches!(
985 parse_into_kind("..foo"),
986 Ok(ExpressionKind::Unary(UnaryOp::RangePre, _))
987 );
988 assert_matches!(
989 parse_into_kind("foo.."),
990 Ok(ExpressionKind::Unary(UnaryOp::RangePost, _))
991 );
992 assert_matches!(
993 parse_into_kind("foo..bar"),
994 Ok(ExpressionKind::Binary(BinaryOp::Range, _, _))
995 );
996 // Parse the nullary "range" operator
997 assert_matches!(parse_into_kind(".."), Ok(ExpressionKind::RangeAll));
998 // Parse the "negate" operator
999 assert_matches!(
1000 parse_into_kind("~ foo"),
1001 Ok(ExpressionKind::Unary(UnaryOp::Negate, _))
1002 );
1003 assert_eq!(
1004 parse_normalized("~ ~~ foo"),
1005 parse_normalized("~(~(~(foo)))"),
1006 );
1007 // Parse the "intersection" operator
1008 assert_matches!(
1009 parse_into_kind("foo & bar"),
1010 Ok(ExpressionKind::Binary(BinaryOp::Intersection, _, _))
1011 );
1012 // Parse the "union" operator
1013 assert_matches!(
1014 parse_into_kind("foo | bar"),
1015 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 2
1016 );
1017 assert_matches!(
1018 parse_into_kind("foo | bar | baz"),
1019 Ok(ExpressionKind::UnionAll(nodes)) if nodes.len() == 3
1020 );
1021 // Parse the "difference" operator
1022 assert_matches!(
1023 parse_into_kind("foo ~ bar"),
1024 Ok(ExpressionKind::Binary(BinaryOp::Difference, _, _))
1025 );
1026 // Parentheses are allowed before suffix operators
1027 assert_eq!(parse_normalized("(foo)-"), parse_normalized("foo-"));
1028 // Space is allowed around expressions
1029 assert_eq!(parse_normalized(" ::foo "), parse_normalized("::foo"));
1030 assert_eq!(parse_normalized("( ::foo )"), parse_normalized("::foo"));
1031 // Space is not allowed around prefix operators
1032 assert_eq!(
1033 parse_into_kind(" :: foo "),
1034 Err(RevsetParseErrorKind::SyntaxError)
1035 );
1036 // Incomplete parse
1037 assert_eq!(
1038 parse_into_kind("foo | -"),
1039 Err(RevsetParseErrorKind::SyntaxError)
1040 );
1041 // Space is allowed around infix operators and function arguments
1042 assert_eq!(
1043 parse_normalized(
1044 " description( arg1 ) ~ file( arg1 , arg2 ) ~ visible_heads( ) ",
1045 ),
1046 parse_normalized("(description(arg1) ~ file(arg1, arg2)) ~ visible_heads()"),
1047 );
1048 // Space is allowed around keyword arguments
1049 assert_eq!(
1050 parse_normalized("remote_bookmarks( remote = foo )"),
1051 parse_normalized("remote_bookmarks(remote=foo)"),
1052 );
1053
1054 // Trailing comma isn't allowed for empty argument
1055 assert!(parse_into_kind("bookmarks(,)").is_err());
1056 // Trailing comma is allowed for the last argument
1057 assert_eq!(
1058 parse_normalized("bookmarks(a,)"),
1059 parse_normalized("bookmarks(a)")
1060 );
1061 assert_eq!(
1062 parse_normalized("bookmarks(a , )"),
1063 parse_normalized("bookmarks(a)")
1064 );
1065 assert!(parse_into_kind("bookmarks(,a)").is_err());
1066 assert!(parse_into_kind("bookmarks(a,,)").is_err());
1067 assert!(parse_into_kind("bookmarks(a , , )").is_err());
1068 assert_eq!(
1069 parse_normalized("file(a,b,)"),
1070 parse_normalized("file(a, b)")
1071 );
1072 assert!(parse_into_kind("file(a,,b)").is_err());
1073 assert_eq!(
1074 parse_normalized("remote_bookmarks(a,remote=b , )"),
1075 parse_normalized("remote_bookmarks(a, remote=b)"),
1076 );
1077 assert!(parse_into_kind("remote_bookmarks(a,,remote=b)").is_err());
1078 }
1079
1080 #[test]
1081 fn test_parse_revset_with_modifier() {
1082 // all: is a program modifier, but all:: isn't
1083 assert_eq!(
1084 parse_into_kind("all:"),
1085 Err(RevsetParseErrorKind::SyntaxError)
1086 );
1087 assert_matches!(
1088 parse_into_kind("all:foo"),
1089 Ok(ExpressionKind::Modifier(modifier)) if modifier.name == "all"
1090 );
1091 assert_matches!(
1092 parse_into_kind("all::"),
1093 Ok(ExpressionKind::Unary(UnaryOp::DagRangePost, _))
1094 );
1095 assert_matches!(
1096 parse_into_kind("all::foo"),
1097 Ok(ExpressionKind::Binary(BinaryOp::DagRange, _, _))
1098 );
1099
1100 // all::: could be parsed as all:(::), but rejected for simplicity
1101 assert_eq!(
1102 parse_into_kind("all:::"),
1103 Err(RevsetParseErrorKind::SyntaxError)
1104 );
1105 assert_eq!(
1106 parse_into_kind("all:::foo"),
1107 Err(RevsetParseErrorKind::SyntaxError)
1108 );
1109
1110 assert_eq!(parse_normalized("all:(foo)"), parse_normalized("all:foo"));
1111 assert_eq!(
1112 parse_normalized("all:all::foo"),
1113 parse_normalized("all:(all::foo)"),
1114 );
1115 assert_eq!(
1116 parse_normalized("all:all | foo"),
1117 parse_normalized("all:(all | foo)"),
1118 );
1119
1120 assert_eq!(
1121 parse_normalized("all: ::foo"),
1122 parse_normalized("all:(::foo)"),
1123 );
1124 assert_eq!(parse_normalized(" all: foo"), parse_normalized("all:foo"));
1125 assert_eq!(
1126 parse_into_kind("(all:foo)"),
1127 Ok(ExpressionKind::StringPattern {
1128 kind: "all",
1129 value: "foo".to_owned()
1130 })
1131 );
1132 assert_matches!(
1133 parse_into_kind("all :foo"),
1134 Err(RevsetParseErrorKind::SyntaxError)
1135 );
1136 assert_eq!(
1137 parse_normalized("all:all:all"),
1138 parse_normalized("all:(all:all)"),
1139 );
1140 }
1141
1142 #[test]
1143 fn test_parse_whitespace() {
1144 let ascii_whitespaces: String = ('\x00'..='\x7f')
1145 .filter(char::is_ascii_whitespace)
1146 .collect();
1147 assert_eq!(
1148 parse_normalized(&format!("{ascii_whitespaces}all()")),
1149 parse_normalized("all()"),
1150 );
1151 }
1152
1153 #[test]
1154 fn test_parse_identifier() {
1155 // Integer is a symbol
1156 assert_eq!(parse_into_kind("0"), Ok(ExpressionKind::Identifier("0")));
1157 // Tag/bookmark name separated by /
1158 assert_eq!(
1159 parse_into_kind("foo_bar/baz"),
1160 Ok(ExpressionKind::Identifier("foo_bar/baz"))
1161 );
1162
1163 // Internal '.', '-', and '+' are allowed
1164 assert_eq!(
1165 parse_into_kind("foo.bar-v1+7"),
1166 Ok(ExpressionKind::Identifier("foo.bar-v1+7"))
1167 );
1168 assert_eq!(
1169 parse_normalized("foo.bar-v1+7-"),
1170 parse_normalized("(foo.bar-v1+7)-")
1171 );
1172 // '.' is not allowed at the beginning or end
1173 assert_eq!(
1174 parse_into_kind(".foo"),
1175 Err(RevsetParseErrorKind::SyntaxError)
1176 );
1177 assert_eq!(
1178 parse_into_kind("foo."),
1179 Err(RevsetParseErrorKind::SyntaxError)
1180 );
1181 // Multiple '.', '-', '+' are not allowed
1182 assert_eq!(
1183 parse_into_kind("foo.+bar"),
1184 Err(RevsetParseErrorKind::SyntaxError)
1185 );
1186 assert_eq!(
1187 parse_into_kind("foo--bar"),
1188 Err(RevsetParseErrorKind::SyntaxError)
1189 );
1190 assert_eq!(
1191 parse_into_kind("foo+-bar"),
1192 Err(RevsetParseErrorKind::SyntaxError)
1193 );
1194
1195 // Parse a parenthesized symbol
1196 assert_eq!(parse_normalized("(foo)"), parse_normalized("foo"));
1197
1198 // Non-ASCII tag/bookmark name
1199 assert_eq!(
1200 parse_into_kind("柔術+jj"),
1201 Ok(ExpressionKind::Identifier("柔術+jj"))
1202 );
1203 }
1204
1205 #[test]
1206 fn test_parse_string_literal() {
1207 // "\<char>" escapes
1208 assert_eq!(
1209 parse_into_kind(r#" "\t\r\n\"\\\0\e" "#),
1210 Ok(ExpressionKind::String("\t\r\n\"\\\0\u{1b}".to_owned()))
1211 );
1212
1213 // Invalid "\<char>" escape
1214 assert_eq!(
1215 parse_into_kind(r#" "\y" "#),
1216 Err(RevsetParseErrorKind::SyntaxError)
1217 );
1218
1219 // Single-quoted raw string
1220 assert_eq!(
1221 parse_into_kind(r#" '' "#),
1222 Ok(ExpressionKind::String("".to_owned()))
1223 );
1224 assert_eq!(
1225 parse_into_kind(r#" 'a\n' "#),
1226 Ok(ExpressionKind::String(r"a\n".to_owned()))
1227 );
1228 assert_eq!(
1229 parse_into_kind(r#" '\' "#),
1230 Ok(ExpressionKind::String(r"\".to_owned()))
1231 );
1232 assert_eq!(
1233 parse_into_kind(r#" '"' "#),
1234 Ok(ExpressionKind::String(r#"""#.to_owned()))
1235 );
1236
1237 // Hex bytes
1238 assert_eq!(
1239 parse_into_kind(r#""\x61\x65\x69\x6f\x75""#),
1240 Ok(ExpressionKind::String("aeiou".to_owned()))
1241 );
1242 assert_eq!(
1243 parse_into_kind(r#""\xe0\xe8\xec\xf0\xf9""#),
1244 Ok(ExpressionKind::String("àèìðù".to_owned()))
1245 );
1246 assert_eq!(
1247 parse_into_kind(r#""\x""#),
1248 Err(RevsetParseErrorKind::SyntaxError)
1249 );
1250 assert_eq!(
1251 parse_into_kind(r#""\xf""#),
1252 Err(RevsetParseErrorKind::SyntaxError)
1253 );
1254 assert_eq!(
1255 parse_into_kind(r#""\xgg""#),
1256 Err(RevsetParseErrorKind::SyntaxError)
1257 );
1258 }
1259
1260 #[test]
1261 fn test_parse_string_pattern() {
1262 assert_eq!(
1263 parse_into_kind(r#"(substring:"foo")"#),
1264 Ok(ExpressionKind::StringPattern {
1265 kind: "substring",
1266 value: "foo".to_owned()
1267 })
1268 );
1269 assert_eq!(
1270 parse_into_kind(r#"("exact:foo")"#),
1271 Ok(ExpressionKind::String("exact:foo".to_owned()))
1272 );
1273 assert_eq!(
1274 parse_normalized(r#"(exact:"foo" )"#),
1275 parse_normalized(r#"(exact:"foo")"#),
1276 );
1277 assert_eq!(
1278 parse_into_kind(r#"(exact:'\')"#),
1279 Ok(ExpressionKind::StringPattern {
1280 kind: "exact",
1281 value: r"\".to_owned()
1282 })
1283 );
1284 assert_matches!(
1285 parse_into_kind(r#"(exact:("foo" ))"#),
1286 Err(RevsetParseErrorKind::NotInfixOperator { .. })
1287 );
1288 }
1289
1290 #[test]
1291 fn parse_at_workspace_and_remote_symbol() {
1292 // Parse "@" (the current working copy)
1293 assert_eq!(parse_into_kind("@"), Ok(ExpressionKind::AtCurrentWorkspace));
1294 assert_eq!(
1295 parse_into_kind("main@"),
1296 Ok(ExpressionKind::AtWorkspace("main".to_owned()))
1297 );
1298 assert_eq!(
1299 parse_into_kind("main@origin"),
1300 Ok(ExpressionKind::RemoteSymbol {
1301 name: "main".to_owned(),
1302 remote: "origin".to_owned()
1303 })
1304 );
1305
1306 // Quoted component in @ expression
1307 assert_eq!(
1308 parse_into_kind(r#""foo bar"@"#),
1309 Ok(ExpressionKind::AtWorkspace("foo bar".to_owned()))
1310 );
1311 assert_eq!(
1312 parse_into_kind(r#""foo bar"@origin"#),
1313 Ok(ExpressionKind::RemoteSymbol {
1314 name: "foo bar".to_owned(),
1315 remote: "origin".to_owned()
1316 })
1317 );
1318 assert_eq!(
1319 parse_into_kind(r#"main@"foo bar""#),
1320 Ok(ExpressionKind::RemoteSymbol {
1321 name: "main".to_owned(),
1322 remote: "foo bar".to_owned()
1323 })
1324 );
1325 assert_eq!(
1326 parse_into_kind(r#"'foo bar'@'bar baz'"#),
1327 Ok(ExpressionKind::RemoteSymbol {
1328 name: "foo bar".to_owned(),
1329 remote: "bar baz".to_owned()
1330 })
1331 );
1332
1333 // Quoted "@" is not interpreted as a working copy or remote symbol
1334 assert_eq!(
1335 parse_into_kind(r#""@""#),
1336 Ok(ExpressionKind::String("@".to_owned()))
1337 );
1338 assert_eq!(
1339 parse_into_kind(r#""main@""#),
1340 Ok(ExpressionKind::String("main@".to_owned()))
1341 );
1342 assert_eq!(
1343 parse_into_kind(r#""main@origin""#),
1344 Ok(ExpressionKind::String("main@origin".to_owned()))
1345 );
1346
1347 // Non-ASCII name
1348 assert_eq!(
1349 parse_into_kind("柔術@"),
1350 Ok(ExpressionKind::AtWorkspace("柔術".to_owned()))
1351 );
1352 assert_eq!(
1353 parse_into_kind("柔@術"),
1354 Ok(ExpressionKind::RemoteSymbol {
1355 name: "柔".to_owned(),
1356 remote: "術".to_owned()
1357 })
1358 );
1359 }
1360
1361 #[test]
1362 fn test_parse_revset_alias_symbol_decl() {
1363 let mut aliases_map = RevsetAliasesMap::new();
1364 // Working copy or remote symbol cannot be used as an alias name.
1365 assert!(aliases_map.insert("@", "none()").is_err());
1366 assert!(aliases_map.insert("a@", "none()").is_err());
1367 assert!(aliases_map.insert("a@b", "none()").is_err());
1368 // Non-ASCII character isn't allowed in alias symbol. This rule can be
1369 // relaxed if needed.
1370 assert!(aliases_map.insert("柔術", "none()").is_err());
1371 }
1372
1373 #[test]
1374 fn test_parse_revset_alias_func_decl() {
1375 let mut aliases_map = RevsetAliasesMap::new();
1376 assert!(aliases_map.insert("5func()", r#""is function 0""#).is_err());
1377 aliases_map.insert("func()", r#""is function 0""#).unwrap();
1378 aliases_map
1379 .insert("func(a, b)", r#""is function 2""#)
1380 .unwrap();
1381 aliases_map.insert("func(a)", r#""is function a""#).unwrap();
1382 aliases_map.insert("func(b)", r#""is function b""#).unwrap();
1383
1384 let (id, params, defn) = aliases_map.get_function("func", 0).unwrap();
1385 assert_eq!(id, AliasId::Function("func", &[]));
1386 assert!(params.is_empty());
1387 assert_eq!(defn, r#""is function 0""#);
1388
1389 let (id, params, defn) = aliases_map.get_function("func", 1).unwrap();
1390 assert_eq!(id, AliasId::Function("func", &["b".to_owned()]));
1391 assert_eq!(params, ["b"]);
1392 assert_eq!(defn, r#""is function b""#);
1393
1394 let (id, params, defn) = aliases_map.get_function("func", 2).unwrap();
1395 assert_eq!(
1396 id,
1397 AliasId::Function("func", &["a".to_owned(), "b".to_owned()])
1398 );
1399 assert_eq!(params, ["a", "b"]);
1400 assert_eq!(defn, r#""is function 2""#);
1401
1402 assert!(aliases_map.get_function("func", 3).is_none());
1403 }
1404
1405 #[test]
1406 fn test_parse_revset_alias_formal_parameter() {
1407 let mut aliases_map = RevsetAliasesMap::new();
1408 // Working copy or remote symbol cannot be used as an parameter name.
1409 assert!(aliases_map.insert("f(@)", "none()").is_err());
1410 assert!(aliases_map.insert("f(a@)", "none()").is_err());
1411 assert!(aliases_map.insert("f(a@b)", "none()").is_err());
1412 // Trailing comma isn't allowed for empty parameter
1413 assert!(aliases_map.insert("f(,)", "none()").is_err());
1414 // Trailing comma is allowed for the last parameter
1415 assert!(aliases_map.insert("g(a,)", "none()").is_ok());
1416 assert!(aliases_map.insert("h(a , )", "none()").is_ok());
1417 assert!(aliases_map.insert("i(,a)", "none()").is_err());
1418 assert!(aliases_map.insert("j(a,,)", "none()").is_err());
1419 assert!(aliases_map.insert("k(a , , )", "none()").is_err());
1420 assert!(aliases_map.insert("l(a,b,)", "none()").is_ok());
1421 assert!(aliases_map.insert("m(a,,b)", "none()").is_err());
1422 }
1423
1424 #[test]
1425 fn test_parse_revset_compat_operator() {
1426 assert_eq!(
1427 parse_into_kind(":foo"),
1428 Err(RevsetParseErrorKind::NotPrefixOperator {
1429 op: ":".to_owned(),
1430 similar_op: "::".to_owned(),
1431 description: "ancestors".to_owned(),
1432 })
1433 );
1434 assert_eq!(
1435 parse_into_kind("foo^"),
1436 Err(RevsetParseErrorKind::NotPostfixOperator {
1437 op: "^".to_owned(),
1438 similar_op: "-".to_owned(),
1439 description: "parents".to_owned(),
1440 })
1441 );
1442 assert_eq!(
1443 parse_into_kind("foo + bar"),
1444 Err(RevsetParseErrorKind::NotInfixOperator {
1445 op: "+".to_owned(),
1446 similar_op: "|".to_owned(),
1447 description: "union".to_owned(),
1448 })
1449 );
1450 assert_eq!(
1451 parse_into_kind("foo - bar"),
1452 Err(RevsetParseErrorKind::NotInfixOperator {
1453 op: "-".to_owned(),
1454 similar_op: "~".to_owned(),
1455 description: "difference".to_owned(),
1456 })
1457 );
1458 }
1459
1460 #[test]
1461 fn test_parse_revset_operator_combinations() {
1462 // Parse repeated "parents" operator
1463 assert_eq!(parse_normalized("foo---"), parse_normalized("((foo-)-)-"));
1464 // Parse repeated "children" operator
1465 assert_eq!(parse_normalized("foo+++"), parse_normalized("((foo+)+)+"));
1466 // Set operator associativity/precedence
1467 assert_eq!(parse_normalized("~x|y"), parse_normalized("(~x)|y"));
1468 assert_eq!(parse_normalized("x&~y"), parse_normalized("x&(~y)"));
1469 assert_eq!(parse_normalized("x~~y"), parse_normalized("x~(~y)"));
1470 assert_eq!(parse_normalized("x~~~y"), parse_normalized("x~(~(~y))"));
1471 assert_eq!(parse_normalized("~x::y"), parse_normalized("~(x::y)"));
1472 assert_eq!(parse_normalized("x|y|z"), parse_normalized("(x|y)|z"));
1473 assert_eq!(parse_normalized("x&y|z"), parse_normalized("(x&y)|z"));
1474 assert_eq!(parse_normalized("x|y&z"), parse_normalized("x|(y&z)"));
1475 assert_eq!(parse_normalized("x|y~z"), parse_normalized("x|(y~z)"));
1476 assert_eq!(parse_normalized("::&.."), parse_normalized("(::)&(..)"));
1477 // Parse repeated "ancestors"/"descendants"/"dag range"/"range" operators
1478 assert_eq!(
1479 parse_into_kind("::foo::"),
1480 Err(RevsetParseErrorKind::SyntaxError)
1481 );
1482 assert_eq!(
1483 parse_into_kind(":::foo"),
1484 Err(RevsetParseErrorKind::SyntaxError)
1485 );
1486 assert_eq!(
1487 parse_into_kind("::::foo"),
1488 Err(RevsetParseErrorKind::SyntaxError)
1489 );
1490 assert_eq!(
1491 parse_into_kind("foo:::"),
1492 Err(RevsetParseErrorKind::SyntaxError)
1493 );
1494 assert_eq!(
1495 parse_into_kind("foo::::"),
1496 Err(RevsetParseErrorKind::SyntaxError)
1497 );
1498 assert_eq!(
1499 parse_into_kind("foo:::bar"),
1500 Err(RevsetParseErrorKind::SyntaxError)
1501 );
1502 assert_eq!(
1503 parse_into_kind("foo::::bar"),
1504 Err(RevsetParseErrorKind::SyntaxError)
1505 );
1506 assert_eq!(
1507 parse_into_kind("::foo::bar"),
1508 Err(RevsetParseErrorKind::SyntaxError)
1509 );
1510 assert_eq!(
1511 parse_into_kind("foo::bar::"),
1512 Err(RevsetParseErrorKind::SyntaxError)
1513 );
1514 assert_eq!(
1515 parse_into_kind("::::"),
1516 Err(RevsetParseErrorKind::SyntaxError)
1517 );
1518 assert_eq!(
1519 parse_into_kind("....foo"),
1520 Err(RevsetParseErrorKind::SyntaxError)
1521 );
1522 assert_eq!(
1523 parse_into_kind("foo...."),
1524 Err(RevsetParseErrorKind::SyntaxError)
1525 );
1526 assert_eq!(
1527 parse_into_kind("foo.....bar"),
1528 Err(RevsetParseErrorKind::SyntaxError)
1529 );
1530 assert_eq!(
1531 parse_into_kind("..foo..bar"),
1532 Err(RevsetParseErrorKind::SyntaxError)
1533 );
1534 assert_eq!(
1535 parse_into_kind("foo..bar.."),
1536 Err(RevsetParseErrorKind::SyntaxError)
1537 );
1538 assert_eq!(
1539 parse_into_kind("...."),
1540 Err(RevsetParseErrorKind::SyntaxError)
1541 );
1542 assert_eq!(
1543 parse_into_kind("::.."),
1544 Err(RevsetParseErrorKind::SyntaxError)
1545 );
1546 // Parse combinations of "parents"/"children" operators and the range operators.
1547 // The former bind more strongly.
1548 assert_eq!(parse_normalized("foo-+"), parse_normalized("(foo-)+"));
1549 assert_eq!(parse_normalized("foo-::"), parse_normalized("(foo-)::"));
1550 assert_eq!(parse_normalized("::foo+"), parse_normalized("::(foo+)"));
1551 assert_eq!(
1552 parse_into_kind("::-"),
1553 Err(RevsetParseErrorKind::SyntaxError)
1554 );
1555 assert_eq!(
1556 parse_into_kind("..+"),
1557 Err(RevsetParseErrorKind::SyntaxError)
1558 );
1559 }
1560
1561 #[test]
1562 fn test_parse_revset_function() {
1563 assert_matches!(
1564 parse_into_kind("parents(foo)"),
1565 Ok(ExpressionKind::FunctionCall(_))
1566 );
1567 assert_eq!(
1568 parse_normalized("parents((foo))"),
1569 parse_normalized("parents(foo)"),
1570 );
1571 assert_eq!(
1572 parse_into_kind("parents(foo"),
1573 Err(RevsetParseErrorKind::SyntaxError)
1574 );
1575 }
1576
1577 #[test]
1578 fn test_expand_symbol_alias() {
1579 assert_eq!(
1580 with_aliases([("AB", "a&b")]).parse_normalized("AB|c"),
1581 parse_normalized("(a&b)|c")
1582 );
1583 assert_eq!(
1584 with_aliases([("AB", "a|b")]).parse_normalized("AB::heads(AB)"),
1585 parse_normalized("(a|b)::heads(a|b)")
1586 );
1587
1588 // Not string substitution 'a&b|c', but tree substitution.
1589 assert_eq!(
1590 with_aliases([("BC", "b|c")]).parse_normalized("a&BC"),
1591 parse_normalized("a&(b|c)")
1592 );
1593
1594 // String literal should not be substituted with alias.
1595 assert_eq!(
1596 with_aliases([("A", "a")]).parse_normalized(r#"A|"A"|'A'"#),
1597 parse_normalized("a|'A'|'A'")
1598 );
1599
1600 // Part of string pattern cannot be substituted.
1601 assert_eq!(
1602 with_aliases([("A", "a")]).parse_normalized("author(exact:A)"),
1603 parse_normalized("author(exact:A)")
1604 );
1605
1606 // Part of @ symbol cannot be substituted.
1607 assert_eq!(
1608 with_aliases([("A", "a")]).parse_normalized("A@"),
1609 parse_normalized("A@")
1610 );
1611 assert_eq!(
1612 with_aliases([("A", "a")]).parse_normalized("A@b"),
1613 parse_normalized("A@b")
1614 );
1615 assert_eq!(
1616 with_aliases([("B", "b")]).parse_normalized("a@B"),
1617 parse_normalized("a@B")
1618 );
1619
1620 // Modifier cannot be substituted.
1621 assert_eq!(
1622 with_aliases([("all", "ALL")]).parse_normalized("all:all"),
1623 parse_normalized("all:ALL")
1624 );
1625
1626 // Top-level alias can be substituted to modifier expression.
1627 assert_eq!(
1628 with_aliases([("A", "all:a")]).parse_normalized("A"),
1629 parse_normalized("all:a")
1630 );
1631
1632 // Multi-level substitution.
1633 assert_eq!(
1634 with_aliases([("A", "BC"), ("BC", "b|C"), ("C", "c")]).parse_normalized("A"),
1635 parse_normalized("b|c")
1636 );
1637
1638 // Infinite recursion, where the top-level error isn't of RecursiveAlias kind.
1639 assert_eq!(
1640 with_aliases([("A", "A")]).parse("A").unwrap_err().kind,
1641 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1642 );
1643 assert_eq!(
1644 with_aliases([("A", "B"), ("B", "b|C"), ("C", "c|B")])
1645 .parse("A")
1646 .unwrap_err()
1647 .kind,
1648 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1649 );
1650
1651 // Error in alias definition.
1652 assert_eq!(
1653 with_aliases([("A", "a(")]).parse("A").unwrap_err().kind,
1654 RevsetParseErrorKind::InAliasExpansion("A".to_owned())
1655 );
1656 }
1657
1658 #[test]
1659 fn test_expand_function_alias() {
1660 assert_eq!(
1661 with_aliases([("F( )", "a")]).parse_normalized("F()"),
1662 parse_normalized("a")
1663 );
1664 assert_eq!(
1665 with_aliases([("F( x )", "x")]).parse_normalized("F(a)"),
1666 parse_normalized("a")
1667 );
1668 assert_eq!(
1669 with_aliases([("F( x, y )", "x|y")]).parse_normalized("F(a, b)"),
1670 parse_normalized("a|b")
1671 );
1672
1673 // Not recursion because functions are overloaded by arity.
1674 assert_eq!(
1675 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "x|y")]).parse_normalized("F(a)"),
1676 parse_normalized("a|b")
1677 );
1678
1679 // Arguments should be resolved in the current scope.
1680 assert_eq!(
1681 with_aliases([("F(x,y)", "x|y")]).parse_normalized("F(a::y,b::x)"),
1682 parse_normalized("(a::y)|(b::x)")
1683 );
1684 // F(a) -> G(a)&y -> (x|a)&y
1685 assert_eq!(
1686 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(a)"),
1687 parse_normalized("(x|a)&y")
1688 );
1689 // F(G(a)) -> F(x|a) -> G(x|a)&y -> (x|(x|a))&y
1690 assert_eq!(
1691 with_aliases([("F(x)", "G(x)&y"), ("G(y)", "x|y")]).parse_normalized("F(G(a))"),
1692 parse_normalized("(x|(x|a))&y")
1693 );
1694
1695 // Function parameter should precede the symbol alias.
1696 assert_eq!(
1697 with_aliases([("F(X)", "X"), ("X", "x")]).parse_normalized("F(a)|X"),
1698 parse_normalized("a|x")
1699 );
1700
1701 // Function parameter shouldn't be expanded in symbol alias.
1702 assert_eq!(
1703 with_aliases([("F(x)", "x|A"), ("A", "x")]).parse_normalized("F(a)"),
1704 parse_normalized("a|x")
1705 );
1706
1707 // String literal should not be substituted with function parameter.
1708 assert_eq!(
1709 with_aliases([("F(x)", r#"x|"x""#)]).parse_normalized("F(a)"),
1710 parse_normalized("a|'x'")
1711 );
1712
1713 // Modifier expression body as parameter.
1714 assert_eq!(
1715 with_aliases([("F(x)", "all:x")]).parse_normalized("F(a|b)"),
1716 parse_normalized("all:(a|b)")
1717 );
1718
1719 // Function and symbol aliases reside in separate namespaces.
1720 assert_eq!(
1721 with_aliases([("A()", "A"), ("A", "a")]).parse_normalized("A()"),
1722 parse_normalized("a")
1723 );
1724
1725 // Invalid number of arguments.
1726 assert_eq!(
1727 with_aliases([("F()", "x")]).parse("F(a)").unwrap_err().kind,
1728 RevsetParseErrorKind::InvalidFunctionArguments {
1729 name: "F".to_owned(),
1730 message: "Expected 0 arguments".to_owned()
1731 }
1732 );
1733 assert_eq!(
1734 with_aliases([("F(x)", "x")]).parse("F()").unwrap_err().kind,
1735 RevsetParseErrorKind::InvalidFunctionArguments {
1736 name: "F".to_owned(),
1737 message: "Expected 1 arguments".to_owned()
1738 }
1739 );
1740 assert_eq!(
1741 with_aliases([("F(x,y)", "x|y")])
1742 .parse("F(a,b,c)")
1743 .unwrap_err()
1744 .kind,
1745 RevsetParseErrorKind::InvalidFunctionArguments {
1746 name: "F".to_owned(),
1747 message: "Expected 2 arguments".to_owned()
1748 }
1749 );
1750 assert_eq!(
1751 with_aliases([("F(x)", "x"), ("F(x,y)", "x|y")])
1752 .parse("F()")
1753 .unwrap_err()
1754 .kind,
1755 RevsetParseErrorKind::InvalidFunctionArguments {
1756 name: "F".to_owned(),
1757 message: "Expected 1 to 2 arguments".to_owned()
1758 }
1759 );
1760 assert_eq!(
1761 with_aliases([("F()", "x"), ("F(x,y)", "x|y")])
1762 .parse("F(a)")
1763 .unwrap_err()
1764 .kind,
1765 RevsetParseErrorKind::InvalidFunctionArguments {
1766 name: "F".to_owned(),
1767 message: "Expected 0, 2 arguments".to_owned()
1768 }
1769 );
1770
1771 // Keyword argument isn't supported for now.
1772 assert_eq!(
1773 with_aliases([("F(x)", "x")])
1774 .parse("F(x=y)")
1775 .unwrap_err()
1776 .kind,
1777 RevsetParseErrorKind::InvalidFunctionArguments {
1778 name: "F".to_owned(),
1779 message: "Unexpected keyword arguments".to_owned()
1780 }
1781 );
1782
1783 // Infinite recursion, where the top-level error isn't of RecursiveAlias kind.
1784 assert_eq!(
1785 with_aliases([("F(x)", "G(x)"), ("G(x)", "H(x)"), ("H(x)", "F(x)")])
1786 .parse("F(a)")
1787 .unwrap_err()
1788 .kind,
1789 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1790 );
1791 assert_eq!(
1792 with_aliases([("F(x)", "F(x,b)"), ("F(x,y)", "F(x|y)")])
1793 .parse("F(a)")
1794 .unwrap_err()
1795 .kind,
1796 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned())
1797 );
1798 }
1799}