977 lines · 33.0 KB · Rust
RawDownload
// 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 std::ascii;use std::collections::HashMap;use std::fmt;use std::slice; use itertools::Itertools as _;use pest::iterators::Pair;use pest::iterators::Pairs;use pest::RuleType; /// Manages diagnostic messages emitted during parsing.////// `T` is usually a parse error type of the language, which contains a message/// and source span of 'static lifetime.#[derive(Debug)]pub struct Diagnostics<T> {    // This might be extended to [{ kind: Warning|Error, message: T }, ..].    diagnostics: Vec<T>,} impl<T> Diagnostics<T> {    /// Creates new empty diagnostics collector.    pub fn new() -> Self {        Diagnostics {            diagnostics: Vec::new(),        }    }     /// Returns `true` if there are no diagnostic messages.    pub fn is_empty(&self) -> bool {        self.diagnostics.is_empty()    }     /// Returns the number of diagnostic messages.    pub fn len(&self) -> usize {        self.diagnostics.len()    }     /// Returns iterator over diagnostic messages.    pub fn iter(&self) -> slice::Iter<'_, T> {        self.diagnostics.iter()    }     /// Adds a diagnostic message of warning level.    pub fn add_warning(&mut self, diag: T) {        self.diagnostics.push(diag);    }     /// Moves diagnostic messages of different type (such as fileset warnings    /// emitted within `file()` revset.)    pub fn extend_with<U>(&mut self, diagnostics: Diagnostics<U>, mut f: impl FnMut(U) -> T) {        self.diagnostics            .extend(diagnostics.diagnostics.into_iter().map(&mut f));    }} impl<T> Default for Diagnostics<T> {    fn default() -> Self {        Self::new()    }} impl<'a, T> IntoIterator for &'a Diagnostics<T> {    type Item = &'a T;    type IntoIter = slice::Iter<'a, T>;     fn into_iter(self) -> Self::IntoIter {        self.iter()    }} /// AST node without type or name checking.#[derive(Clone, Debug, Eq, PartialEq)]pub struct ExpressionNode<'i, T> {    /// Expression item such as identifier, literal, function call, etc.    pub kind: T,    /// Span of the node.    pub span: pest::Span<'i>,} impl<'i, T> ExpressionNode<'i, T> {    /// Wraps the given expression and span.    pub fn new(kind: T, span: pest::Span<'i>) -> Self {        ExpressionNode { kind, span }    }} /// Function call in AST.#[derive(Clone, Debug, Eq, PartialEq)]pub struct FunctionCallNode<'i, T> {    /// Function name.    pub name: &'i str,    /// Span of the function name.    pub name_span: pest::Span<'i>,    /// List of positional arguments.    pub args: Vec<ExpressionNode<'i, T>>,    /// List of keyword arguments.    pub keyword_args: Vec<KeywordArgument<'i, T>>,    /// Span of the arguments list.    pub args_span: pest::Span<'i>,} /// Keyword argument pair in AST.#[derive(Clone, Debug, Eq, PartialEq)]pub struct KeywordArgument<'i, T> {    /// Parameter name.    pub name: &'i str,    /// Span of the parameter name.    pub name_span: pest::Span<'i>,    /// Value expression.    pub value: ExpressionNode<'i, T>,} impl<'i, T> FunctionCallNode<'i, T> {    /// Number of arguments assuming named arguments are all unique.    pub fn arity(&self) -> usize {        self.args.len() + self.keyword_args.len()    }     /// Ensures that no arguments passed.    pub fn expect_no_arguments(&self) -> Result<(), InvalidArguments<'i>> {        let ([], []) = self.expect_arguments()?;        Ok(())    }     /// Extracts exactly N required arguments.    pub fn expect_exact_arguments<const N: usize>(        &self,    ) -> Result<&[ExpressionNode<'i, T>; N], InvalidArguments<'i>> {        let (args, []) = self.expect_arguments()?;        Ok(args)    }     /// Extracts N required arguments and remainders.    #[expect(clippy::type_complexity)]    pub fn expect_some_arguments<const N: usize>(        &self,    ) -> Result<(&[ExpressionNode<'i, T>; N], &[ExpressionNode<'i, T>]), InvalidArguments<'i>> {        self.ensure_no_keyword_arguments()?;        if self.args.len() >= N {            let (required, rest) = self.args.split_at(N);            Ok((required.try_into().unwrap(), rest))        } else {            Err(self.invalid_arguments_count(N, None))        }    }     /// Extracts N required arguments and M optional arguments.    #[expect(clippy::type_complexity)]    pub fn expect_arguments<const N: usize, const M: usize>(        &self,    ) -> Result<        (            &[ExpressionNode<'i, T>; N],            [Option<&ExpressionNode<'i, T>>; M],        ),        InvalidArguments<'i>,    > {        self.ensure_no_keyword_arguments()?;        let count_range = N..=(N + M);        if count_range.contains(&self.args.len()) {            let (required, rest) = self.args.split_at(N);            let mut optional = rest.iter().map(Some).collect_vec();            optional.resize(M, None);            Ok((                required.try_into().unwrap(),                optional.try_into().ok().unwrap(),            ))        } else {            let (min, max) = count_range.into_inner();            Err(self.invalid_arguments_count(min, Some(max)))        }    }     /// Extracts N required arguments and M optional arguments. Some of them can    /// be specified as keyword arguments.    ///    /// `names` is a list of parameter names. Unnamed positional arguments    /// should be padded with `""`.    #[expect(clippy::type_complexity)]    pub fn expect_named_arguments<const N: usize, const M: usize>(        &self,        names: &[&str],    ) -> Result<        (            [&ExpressionNode<'i, T>; N],            [Option<&ExpressionNode<'i, T>>; M],        ),        InvalidArguments<'i>,    > {        if self.keyword_args.is_empty() {            let (required, optional) = self.expect_arguments::<N, M>()?;            Ok((required.each_ref(), optional))        } else {            let (required, optional) = self.expect_named_arguments_vec(names, N, N + M)?;            Ok((                required.try_into().ok().unwrap(),                optional.try_into().ok().unwrap(),            ))        }    }     #[expect(clippy::type_complexity)]    fn expect_named_arguments_vec(        &self,        names: &[&str],        min: usize,        max: usize,    ) -> Result<        (            Vec<&ExpressionNode<'i, T>>,            Vec<Option<&ExpressionNode<'i, T>>>,        ),        InvalidArguments<'i>,    > {        assert!(names.len() <= max);         if self.args.len() > max {            return Err(self.invalid_arguments_count(min, Some(max)));        }        let mut extracted = Vec::with_capacity(max);        extracted.extend(self.args.iter().map(Some));        extracted.resize(max, None);         for arg in &self.keyword_args {            let name = arg.name;            let span = arg.name_span.start_pos().span(&arg.value.span.end_pos());            let pos = names.iter().position(|&n| n == name).ok_or_else(|| {                self.invalid_arguments(format!(r#"Unexpected keyword argument "{name}""#), span)            })?;            if extracted[pos].is_some() {                return Err(self.invalid_arguments(                    format!(r#"Got multiple values for keyword "{name}""#),                    span,                ));            }            extracted[pos] = Some(&arg.value);        }         let optional = extracted.split_off(min);        let required = extracted.into_iter().flatten().collect_vec();        if required.len() != min {            return Err(self.invalid_arguments_count(min, Some(max)));        }        Ok((required, optional))    }     fn ensure_no_keyword_arguments(&self) -> Result<(), InvalidArguments<'i>> {        if let (Some(first), Some(last)) = (self.keyword_args.first(), self.keyword_args.last()) {            let span = first.name_span.start_pos().span(&last.value.span.end_pos());            Err(self.invalid_arguments("Unexpected keyword arguments".to_owned(), span))        } else {            Ok(())        }    }     fn invalid_arguments(&self, message: String, span: pest::Span<'i>) -> InvalidArguments<'i> {        InvalidArguments {            name: self.name,            message,            span,        }    }     fn invalid_arguments_count(&self, min: usize, max: Option<usize>) -> InvalidArguments<'i> {        let message = match (min, max) {            (min, Some(max)) if min == max => format!("Expected {min} arguments"),            (min, Some(max)) => format!("Expected {min} to {max} arguments"),            (min, None) => format!("Expected at least {min} arguments"),        };        self.invalid_arguments(message, self.args_span)    }     fn invalid_arguments_count_with_arities(        &self,        arities: impl IntoIterator<Item = usize>,    ) -> InvalidArguments<'i> {        let message = format!("Expected {} arguments", arities.into_iter().join(", "));        self.invalid_arguments(message, self.args_span)    }} /// Unexpected number of arguments, or invalid combination of arguments.////// This error is supposed to be converted to language-specific parse error/// type, where lifetime `'i` will be eliminated.#[derive(Clone, Debug)]pub struct InvalidArguments<'i> {    /// Function name.    pub name: &'i str,    /// Error message.    pub message: String,    /// Span of the bad arguments.    pub span: pest::Span<'i>,} /// Expression item that can be transformed recursively by using `folder: F`.pub trait FoldableExpression<'i>: Sized {    /// Transforms `self` by applying the `folder` to inner items.    fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>    where        F: ExpressionFolder<'i, Self> + ?Sized;} /// Visitor-like interface to transform AST nodes recursively.pub trait ExpressionFolder<'i, T: FoldableExpression<'i>> {    /// Transform error.    type Error;     /// Transforms the expression `node`. By default, inner items are    /// transformed recursively.    fn fold_expression(        &mut self,        node: ExpressionNode<'i, T>,    ) -> Result<ExpressionNode<'i, T>, Self::Error> {        let ExpressionNode { kind, span } = node;        let kind = kind.fold(self, span)?;        Ok(ExpressionNode { kind, span })    }     /// Transforms identifier.    fn fold_identifier(&mut self, name: &'i str, span: pest::Span<'i>) -> Result<T, Self::Error>;     /// Transforms function call.    fn fold_function_call(        &mut self,        function: Box<FunctionCallNode<'i, T>>,        span: pest::Span<'i>,    ) -> Result<T, Self::Error>;} /// Transforms list of `nodes` by using `folder`.pub fn fold_expression_nodes<'i, F, T>(    folder: &mut F,    nodes: Vec<ExpressionNode<'i, T>>,) -> Result<Vec<ExpressionNode<'i, T>>, F::Error>where    F: ExpressionFolder<'i, T> + ?Sized,    T: FoldableExpression<'i>,{    nodes        .into_iter()        .map(|node| folder.fold_expression(node))        .try_collect()} /// Transforms function call arguments by using `folder`.pub fn fold_function_call_args<'i, F, T>(    folder: &mut F,    function: FunctionCallNode<'i, T>,) -> Result<FunctionCallNode<'i, T>, F::Error>where    F: ExpressionFolder<'i, T> + ?Sized,    T: FoldableExpression<'i>,{    Ok(FunctionCallNode {        name: function.name,        name_span: function.name_span,        args: fold_expression_nodes(folder, function.args)?,        keyword_args: function            .keyword_args            .into_iter()            .map(|arg| {                Ok(KeywordArgument {                    name: arg.name,                    name_span: arg.name_span,                    value: folder.fold_expression(arg.value)?,                })            })            .try_collect()?,        args_span: function.args_span,    })} /// 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'),                    "e" => result.push('\x1b'),                    hex if hex.starts_with('x') => {                        result.push(char::from(                            u8::from_str_radix(&hex[1..], 16).expect("hex characters"),                        ));                    }                    char => panic!("invalid escape: \\{char:?}"),                }            } else {                panic!("unexpected part of string: {part:?}");            }        }        result    }} /// Escape special characters in the inputpub fn escape_string(unescaped: &str) -> String {    let mut escaped = String::with_capacity(unescaped.len());    for c in unescaped.chars() {        match c {            '"' => escaped.push_str(r#"\""#),            '\\' => escaped.push_str(r#"\\"#),            '\t' => escaped.push_str(r#"\t"#),            '\r' => escaped.push_str(r#"\r"#),            '\n' => escaped.push_str(r#"\n"#),            '\0' => escaped.push_str(r#"\0"#),            c if c.is_ascii_control() => {                for b in ascii::escape_default(c as u8) {                    escaped.push(b as char);                }            }            c => escaped.push(c),        }    }    escaped} /// Helper to parse function call.#[derive(Debug)]pub struct FunctionCallParser<R> {    /// Function name.    pub function_name_rule: R,    /// List of positional and keyword arguments.    pub function_arguments_rule: R,    /// Pair of parameter name and value.    pub keyword_argument_rule: R,    /// Parameter name.    pub argument_name_rule: R,    /// Value expression.    pub argument_value_rule: R,} impl<R: RuleType> FunctionCallParser<R> {    /// Parses the given `pair` as function call.    pub fn parse<'i, T, E: From<InvalidArguments<'i>>>(        &self,        pair: Pair<'i, R>,        // parse_name can be defined for any Pair<'_, R>, but parse_value should        // be allowed to construct T by capturing Pair<'i, R>.        parse_name: impl Fn(Pair<'i, R>) -> Result<&'i str, E>,        parse_value: impl Fn(Pair<'i, R>) -> Result<ExpressionNode<'i, T>, E>,    ) -> Result<FunctionCallNode<'i, T>, E> {        let (name_pair, args_pair) = pair.into_inner().collect_tuple().unwrap();        assert_eq!(name_pair.as_rule(), self.function_name_rule);        assert_eq!(args_pair.as_rule(), self.function_arguments_rule);        let name_span = name_pair.as_span();        let args_span = args_pair.as_span();        let function_name = parse_name(name_pair)?;        let mut args = Vec::new();        let mut keyword_args = Vec::new();        for pair in args_pair.into_inner() {            let span = pair.as_span();            if pair.as_rule() == self.argument_value_rule {                if !keyword_args.is_empty() {                    return Err(InvalidArguments {                        name: function_name,                        message: "Positional argument follows keyword argument".to_owned(),                        span,                    }                    .into());                }                args.push(parse_value(pair)?);            } else if pair.as_rule() == self.keyword_argument_rule {                let (name_pair, value_pair) = pair.into_inner().collect_tuple().unwrap();                assert_eq!(name_pair.as_rule(), self.argument_name_rule);

Lines 1–500 of 977.