just playing with tangled
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

revset: add support for local variables expansion

I think this can be used in order to substitute remote name in the default push
revset expression?

push(remote) = remote_bookmarks(remote=remote)..@

+69 -12
+29 -4
lib/src/dsl_util.rs
··· 712 712 713 713 /// Expands aliases recursively in tree of `T`. 714 714 #[derive(Debug)] 715 - struct AliasExpander<'i, T, P> { 715 + struct AliasExpander<'i, 'a, T, P> { 716 716 /// Alias symbols and functions that are globally available. 717 717 aliases_map: &'i AliasesMap<P, String>, 718 + /// Local variables set in the outermost scope. 719 + locals: &'a HashMap<&'i str, ExpressionNode<'i, T>>, 718 720 /// Stack of aliases and local parameters currently expanding. 719 721 states: Vec<AliasExpandingState<'i, T>>, 720 722 } ··· 725 727 locals: HashMap<&'i str, ExpressionNode<'i, T>>, 726 728 } 727 729 728 - impl<'i, T, P, E> AliasExpander<'i, T, P> 730 + impl<'i, T, P, E> AliasExpander<'i, '_, T, P> 729 731 where 730 732 T: AliasExpandableExpression<'i> + Clone, 731 733 P: AliasDefinitionParser<Output<'i> = T, Error = E>, 732 734 E: AliasExpandError, 733 735 { 736 + /// Local variables available to the current scope. 737 + fn current_locals(&self) -> &HashMap<&'i str, ExpressionNode<'i, T>> { 738 + self.states.last().map_or(self.locals, |s| &s.locals) 739 + } 740 + 734 741 fn expand_defn( 735 742 &mut self, 736 743 id: AliasId<'i>, ··· 756 763 } 757 764 } 758 765 759 - impl<'i, T, P, E> ExpressionFolder<'i, T> for AliasExpander<'i, T, P> 766 + impl<'i, T, P, E> ExpressionFolder<'i, T> for AliasExpander<'i, '_, T, P> 760 767 where 761 768 T: AliasExpandableExpression<'i> + Clone, 762 769 P: AliasDefinitionParser<Output<'i> = T, Error = E>, ··· 765 772 type Error = E; 766 773 767 774 fn fold_identifier(&mut self, name: &'i str, span: pest::Span<'i>) -> Result<T, Self::Error> { 768 - if let Some(subst) = self.states.last().and_then(|s| s.locals.get(name)) { 775 + if let Some(subst) = self.current_locals().get(name) { 769 776 let id = AliasId::Parameter(name); 770 777 Ok(T::alias_expanded(id, Box::new(subst.clone()))) 771 778 } else if let Some((id, defn)) = self.aliases_map.get_symbol(name) { ··· 820 827 P: AliasDefinitionParser<Output<'i> = T>, 821 828 P::Error: AliasExpandError, 822 829 { 830 + expand_aliases_with_locals(node, aliases_map, &HashMap::new()) 831 + } 832 + 833 + /// Expands aliases recursively with the outermost local variables. 834 + /// 835 + /// Local variables are similar to alias symbols, but are scoped. Alias symbols 836 + /// are globally accessible from alias expressions, but local variables aren't. 837 + pub fn expand_aliases_with_locals<'i, T, P>( 838 + node: ExpressionNode<'i, T>, 839 + aliases_map: &'i AliasesMap<P, String>, 840 + locals: &HashMap<&'i str, ExpressionNode<'i, T>>, 841 + ) -> Result<ExpressionNode<'i, T>, P::Error> 842 + where 843 + T: AliasExpandableExpression<'i> + Clone, 844 + P: AliasDefinitionParser<Output<'i> = T>, 845 + P::Error: AliasExpandError, 846 + { 823 847 let mut expander = AliasExpander { 824 848 aliases_map, 849 + locals, 825 850 states: Vec::new(), 826 851 }; 827 852 expander.fold_expression(node)
+40 -8
lib/src/revset_parser.rs
··· 843 843 844 844 #[cfg(test)] 845 845 mod tests { 846 + use std::collections::HashMap; 847 + 846 848 use assert_matches::assert_matches; 847 849 848 850 use super::*; 849 851 use crate::dsl_util::KeywordArgument; 850 852 851 853 #[derive(Debug)] 852 - struct WithRevsetAliasesMap(RevsetAliasesMap); 854 + struct WithRevsetAliasesMap<'i> { 855 + aliases_map: RevsetAliasesMap, 856 + locals: HashMap<&'i str, ExpressionNode<'i>>, 857 + } 858 + 859 + impl<'i> WithRevsetAliasesMap<'i> { 860 + fn set_local(mut self, name: &'i str, value: &'i str) -> Self { 861 + self.locals.insert(name, parse_program(value).unwrap()); 862 + self 863 + } 853 864 854 - impl WithRevsetAliasesMap { 855 - fn parse<'i>(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> { 865 + fn parse(&'i self, text: &'i str) -> Result<ExpressionNode<'i>, RevsetParseError> { 856 866 let node = parse_program(text)?; 857 - dsl_util::expand_aliases(node, &self.0) 867 + dsl_util::expand_aliases_with_locals(node, &self.aliases_map, &self.locals) 858 868 } 859 869 860 - fn parse_normalized<'i>(&'i self, text: &'i str) -> ExpressionNode<'i> { 870 + fn parse_normalized(&'i self, text: &'i str) -> ExpressionNode<'i> { 861 871 normalize_tree(self.parse(text).unwrap()) 862 872 } 863 873 } 864 874 865 - fn with_aliases( 875 + fn with_aliases<'i>( 866 876 aliases: impl IntoIterator<Item = (impl AsRef<str>, impl Into<String>)>, 867 - ) -> WithRevsetAliasesMap { 877 + ) -> WithRevsetAliasesMap<'i> { 868 878 let mut aliases_map = RevsetAliasesMap::new(); 869 879 for (decl, defn) in aliases { 870 880 aliases_map.insert(decl, defn).unwrap(); 871 881 } 872 - WithRevsetAliasesMap(aliases_map) 882 + WithRevsetAliasesMap { 883 + aliases_map, 884 + locals: HashMap::new(), 885 + } 873 886 } 874 887 875 888 fn parse_into_kind(text: &str) -> Result<ExpressionKind, RevsetParseErrorKind> { ··· 1836 1849 .unwrap_err() 1837 1850 .kind, 1838 1851 RevsetParseErrorKind::InAliasExpansion("F(x)".to_owned()) 1852 + ); 1853 + } 1854 + 1855 + #[test] 1856 + fn test_expand_with_locals() { 1857 + // Local variable should precede the symbol alias. 1858 + assert_eq!( 1859 + with_aliases([("A", "symbol")]) 1860 + .set_local("A", "local") 1861 + .parse_normalized("A"), 1862 + parse_normalized("local") 1863 + ); 1864 + 1865 + // Local variable shouldn't be expanded within aliases. 1866 + assert_eq!( 1867 + with_aliases([("B", "A"), ("F(x)", "x&A")]) 1868 + .set_local("A", "a") 1869 + .parse_normalized("A|B|F(A)"), 1870 + parse_normalized("a|A|(a&A)") 1839 1871 ); 1840 1872 } 1841 1873 }