ok/jj
1
0
Fork 0
forked from mirrors/jj

revset: backport \-escapes parsing from templater

This commit is contained in:
Yuya Nishihara 2024-04-07 16:10:17 +09:00
parent d1ae2d72c8
commit d442cd872f
3 changed files with 39 additions and 15 deletions

View file

@ -32,6 +32,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed bugs
* Revsets now support `\`-escapes in string literal.
## [0.16.0] - 2024-04-03
### Deprecations

View file

@ -21,7 +21,12 @@ symbol = {
identifier
| string_literal
}
string_literal = { "\"" ~ (!"\"" ~ ANY)* ~ "\"" }
string_escape = @{ "\\" ~ ("t" | "r" | "n" | "0" | "\"" | "\\") }
string_content_char = @{ !("\"" | "\\") ~ ANY }
string_content = @{ string_content_char+ }
string_literal = ${ "\"" ~ (string_content | string_escape)* ~ "\"" }
whitespace = _{ " " | "\t" | "\r" | "\n" | "\x0c" }
at_op = { "@" }

View file

@ -33,6 +33,7 @@ use thiserror::Error;
use crate::backend::{BackendError, BackendResult, ChangeId, CommitId};
use crate::commit::Commit;
use crate::dsl_util::StringLiteralParser;
use crate::fileset::{FilePattern, FilesetExpression, FilesetParseContext};
use crate::git;
use crate::hex_util::to_forward_hex;
@ -76,6 +77,11 @@ pub enum RevsetEvaluationError {
#[grammar = "revset.pest"]
pub struct RevsetParser;
const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser {
content_rule: Rule::string_content,
escape_rule: Rule::string_escape,
};
impl Rule {
/// Whether this is a placeholder rule for compatibility with the other
/// systems.
@ -97,6 +103,9 @@ impl Rule {
Rule::identifier_part => None,
Rule::identifier => None,
Rule::symbol => None,
Rule::string_escape => None,
Rule::string_content_char => None,
Rule::string_content => None,
Rule::string_literal => None,
Rule::whitespace => None,
Rule::at_op => Some("@"),
@ -1090,7 +1099,9 @@ fn parse_symbol_rule(
Ok(RevsetExpression::symbol(name.to_owned()))
}
}
Rule::string_literal => parse_string_literal(first).map(RevsetExpression::symbol),
Rule::string_literal => Ok(RevsetExpression::symbol(
STRING_LITERAL_PARSER.parse(first.into_inner()),
)),
_ => {
panic!("unexpected symbol parse rule: {:?}", first.as_str());
}
@ -1102,25 +1113,13 @@ fn parse_symbol_rule_as_literal(mut pairs: Pairs<Rule>) -> Result<String, Revset
let first = pairs.next().unwrap();
match first.as_rule() {
Rule::identifier => Ok(first.as_str().to_owned()),
Rule::string_literal => parse_string_literal(first),
Rule::string_literal => Ok(STRING_LITERAL_PARSER.parse(first.into_inner())),
_ => {
panic!("unexpected symbol parse rule: {:?}", first.as_str());
}
}
}
// TODO: Add support for \-escape syntax
fn parse_string_literal(pair: Pair<Rule>) -> Result<String, RevsetParseError> {
assert_eq!(pair.as_rule(), Rule::string_literal);
Ok(pair
.as_str()
.strip_prefix('"')
.unwrap()
.strip_suffix('"')
.unwrap()
.to_owned())
}
fn parse_function_expression(
name_pair: Pair<Rule>,
arguments_pair: Pair<Rule>,
@ -3084,6 +3083,23 @@ mod tests {
);
}
#[test]
fn test_parse_string_literal() {
// "\<char>" escapes
assert_eq!(
parse(r#"branches("\t\r\n\"\\\0")"#),
Ok(RevsetExpression::branches(StringPattern::Substring(
"\t\r\n\"\\\0".to_owned()
)))
);
// Invalid "\<char>" escape
assert_eq!(
parse(r#"branches("\y")"#),
Err(RevsetParseErrorKind::SyntaxError)
);
}
#[test]
fn test_parse_string_pattern() {
assert_eq!(