dsl_util: extract helper that parses string literal with \-escapes

The top-level assertion is removed since it's now obvious that the pair
represents a Rule::string_literal.
This commit is contained in:
Yuya Nishihara 2024-04-07 14:52:16 +09:00
parent 46b4c68325
commit 274183fa66
3 changed files with 60 additions and 24 deletions

View file

@ -16,6 +16,7 @@ use std::collections::HashMap;
use std::{error, fmt, mem};
use itertools::Itertools as _;
use jj_lib::dsl_util::StringLiteralParser;
use once_cell::sync::Lazy;
use pest::iterators::{Pair, Pairs};
use pest::pratt_parser::{Assoc, Op, PrattParser};
@ -27,6 +28,11 @@ use thiserror::Error;
#[grammar = "template.pest"]
struct TemplateParser;
const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser {
content_rule: Rule::string_content,
escape_rule: Rule::string_escape,
};
impl Rule {
fn to_symbol(self) -> Option<&'static str> {
match self {
@ -314,29 +320,6 @@ fn parse_identifier_name(pair: Pair<Rule>) -> TemplateParseResult<&str> {
}
}
fn parse_string_literal(pair: Pair<Rule>) -> String {
assert_eq!(pair.as_rule(), Rule::string_literal);
let mut result = String::new();
for part in pair.into_inner() {
match part.as_rule() {
Rule::string_content => {
result.push_str(part.as_str());
}
Rule::string_escape => match &part.as_str()[1..] {
"\"" => result.push('"'),
"\\" => result.push('\\'),
"t" => result.push('\t'),
"r" => result.push('\r'),
"n" => result.push('\n'),
"0" => result.push('\0'),
char => panic!("invalid escape: \\{char:?}"),
},
_ => panic!("unexpected part of string: {part:?}"),
}
}
result
}
fn parse_formal_parameters(params_pair: Pair<Rule>) -> TemplateParseResult<Vec<&str>> {
assert_eq!(params_pair.as_rule(), Rule::formal_parameters);
let params_span = params_pair.as_span();
@ -397,7 +380,7 @@ fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {
let span = expr.as_span();
let primary = match expr.as_rule() {
Rule::string_literal => {
let text = parse_string_literal(expr);
let text = STRING_LITERAL_PARSER.parse(expr.into_inner());
ExpressionNode::new(ExpressionKind::String(text), span)
}
Rule::integer_literal => {

52
lib/src/dsl_util.rs Normal file
View file

@ -0,0 +1,52 @@
// Copyright 2020-2024 The Jujutsu Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Domain-specific language helpers.
use pest::iterators::Pairs;
use pest::RuleType;
/// Helper to parse string literal.
#[derive(Debug)]
pub struct StringLiteralParser<R> {
/// String content part.
pub content_rule: R,
/// Escape sequence part including backslash character.
pub escape_rule: R,
}
impl<R: RuleType> StringLiteralParser<R> {
/// Parses the given string literal `pairs` into string.
pub fn parse(&self, pairs: Pairs<R>) -> String {
let mut result = String::new();
for part in pairs {
if part.as_rule() == self.content_rule {
result.push_str(part.as_str());
} else if part.as_rule() == self.escape_rule {
match &part.as_str()[1..] {
"\"" => result.push('"'),
"\\" => result.push('\\'),
"t" => result.push('\t'),
"r" => result.push('\r'),
"n" => result.push('\n'),
"0" => result.push('\0'),
char => panic!("invalid escape: \\{char:?}"),
}
} else {
panic!("unexpected part of string: {part:?}");
}
}
result
}
}

View file

@ -36,6 +36,7 @@ pub mod dag_walk;
pub mod default_index;
pub mod default_submodule_store;
pub mod diff;
pub mod dsl_util;
pub mod extensions_map;
pub mod file_util;
pub mod files;