1350 lines · 47.7 KB · Rust
RawDownload
// Copyright 2020 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. use std::collections::HashMap;use std::error;use std::mem; use itertools::Itertools as _;use jj_lib::dsl_util;use jj_lib::dsl_util::collect_similar;use jj_lib::dsl_util::AliasDeclaration;use jj_lib::dsl_util::AliasDeclarationParser;use jj_lib::dsl_util::AliasDefinitionParser;use jj_lib::dsl_util::AliasExpandError;use jj_lib::dsl_util::AliasExpandableExpression;use jj_lib::dsl_util::AliasId;use jj_lib::dsl_util::AliasesMap;use jj_lib::dsl_util::Diagnostics;use jj_lib::dsl_util::ExpressionFolder;use jj_lib::dsl_util::FoldableExpression;use jj_lib::dsl_util::FunctionCallParser;use jj_lib::dsl_util::InvalidArguments;use jj_lib::dsl_util::StringLiteralParser;use once_cell::sync::Lazy;use pest::iterators::Pair;use pest::iterators::Pairs;use pest::pratt_parser::Assoc;use pest::pratt_parser::Op;use pest::pratt_parser::PrattParser;use pest::Parser as _;use pest_derive::Parser;use thiserror::Error; #[derive(Parser)]#[grammar = "template.pest"]struct TemplateParser; const STRING_LITERAL_PARSER: StringLiteralParser<Rule> = StringLiteralParser {    content_rule: Rule::string_content,    escape_rule: Rule::string_escape,};const FUNCTION_CALL_PARSER: FunctionCallParser<Rule> = FunctionCallParser {    function_name_rule: Rule::identifier,    function_arguments_rule: Rule::function_arguments,    keyword_argument_rule: Rule::keyword_argument,    argument_name_rule: Rule::identifier,    argument_value_rule: Rule::template,}; impl Rule {    fn to_symbol(self) -> Option<&'static str> {        match self {            Rule::EOI => None,            Rule::whitespace => None,            Rule::string_escape => None,            Rule::string_content_char => None,            Rule::string_content => None,            Rule::string_literal => None,            Rule::raw_string_content => None,            Rule::raw_string_literal => None,            Rule::integer_literal => None,            Rule::identifier => None,            Rule::concat_op => Some("++"),            Rule::logical_or_op => Some("||"),            Rule::logical_and_op => Some("&&"),            Rule::eq_op => Some("=="),            Rule::ne_op => Some("!="),            Rule::ge_op => Some(">="),            Rule::gt_op => Some(">"),            Rule::le_op => Some("<="),            Rule::lt_op => Some("<"),            Rule::logical_not_op => Some("!"),            Rule::negate_op => Some("-"),            Rule::prefix_ops => None,            Rule::infix_ops => None,            Rule::function => None,            Rule::keyword_argument => None,            Rule::argument => None,            Rule::function_arguments => None,            Rule::lambda => None,            Rule::formal_parameters => None,            Rule::primary => None,            Rule::term => None,            Rule::expression => None,            Rule::template => None,            Rule::program => None,            Rule::function_alias_declaration => None,            Rule::alias_declaration => None,        }    }} /// Manages diagnostic messages emitted during template parsing and building.pub type TemplateDiagnostics = Diagnostics<TemplateParseError>; pub type TemplateParseResult<T> = Result<T, TemplateParseError>; #[derive(Debug, Error)]#[error("{pest_error}")]pub struct TemplateParseError {    kind: TemplateParseErrorKind,    pest_error: Box<pest::error::Error<Rule>>,    source: Option<Box<dyn error::Error + Send + Sync>>,} #[derive(Clone, Debug, Eq, Error, PartialEq)]pub enum TemplateParseErrorKind {    #[error("Syntax error")]    SyntaxError,    #[error("Keyword `{name}` doesn't exist")]    NoSuchKeyword {        name: String,        candidates: Vec<String>,    },    #[error("Function `{name}` doesn't exist")]    NoSuchFunction {        name: String,        candidates: Vec<String>,    },    #[error("Method `{name}` doesn't exist for type `{type_name}`")]    NoSuchMethod {        type_name: String,        name: String,        candidates: Vec<String>,    },    #[error("Function `{name}`: {message}")]    InvalidArguments { name: String, message: String },    #[error("Redefinition of function parameter")]    RedefinedFunctionParameter,    #[error("{0}")]    Expression(String),    #[error("In alias `{0}`")]    InAliasExpansion(String),    #[error("In function parameter `{0}`")]    InParameterExpansion(String),    #[error("Alias `{0}` expanded recursively")]    RecursiveAlias(String),} impl TemplateParseError {    pub fn with_span(kind: TemplateParseErrorKind, span: pest::Span<'_>) -> Self {        let message = kind.to_string();        let pest_error = Box::new(pest::error::Error::new_from_span(            pest::error::ErrorVariant::CustomError { message },            span,        ));        TemplateParseError {            kind,            pest_error,            source: None,        }    }     pub fn with_source(mut self, source: impl Into<Box<dyn error::Error + Send + Sync>>) -> Self {        self.source = Some(source.into());        self    }     // TODO: migrate all callers to table-based lookup_method()    pub(crate) fn no_such_method(        type_name: impl Into<String>,        function: &FunctionCallNode,    ) -> Self {        TemplateParseError::with_span(            TemplateParseErrorKind::NoSuchMethod {                type_name: type_name.into(),                name: function.name.to_owned(),                candidates: vec![],            },            function.name_span,        )    }     pub fn expected_type(expected: &str, actual: &str, span: pest::Span<'_>) -> Self {        let message =            format!("Expected expression of type `{expected}`, but actual type is `{actual}`");        TemplateParseError::expression(message, span)    }     /// Some other expression error.    pub fn expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {        TemplateParseError::with_span(TemplateParseErrorKind::Expression(message.into()), span)    }     /// If this is a `NoSuchKeyword` error, expands the candidates list with the    /// given `other_keywords`.    pub fn extend_keyword_candidates<I>(mut self, other_keywords: I) -> Self    where        I: IntoIterator,        I::Item: AsRef<str>,    {        if let TemplateParseErrorKind::NoSuchKeyword { name, candidates } = &mut self.kind {            let other_candidates = collect_similar(name, other_keywords);            *candidates = itertools::merge(mem::take(candidates), other_candidates)                .dedup()                .collect();        }        self    }     /// If this is a `NoSuchFunction` error, expands the candidates list with    /// the given `other_functions`.    pub fn extend_function_candidates<I>(mut self, other_functions: I) -> Self    where        I: IntoIterator,        I::Item: AsRef<str>,    {        if let TemplateParseErrorKind::NoSuchFunction { name, candidates } = &mut self.kind {            let other_candidates = collect_similar(name, other_functions);            *candidates = itertools::merge(mem::take(candidates), other_candidates)                .dedup()                .collect();        }        self    }     /// Expands keyword/function candidates with the given aliases.    pub fn extend_alias_candidates(self, aliases_map: &TemplateAliasesMap) -> Self {        self.extend_keyword_candidates(aliases_map.symbol_names())            .extend_function_candidates(aliases_map.function_names())    }     pub fn kind(&self) -> &TemplateParseErrorKind {        &self.kind    }     /// Original parsing error which typically occurred in an alias expression.    pub fn origin(&self) -> Option<&Self> {        self.source.as_ref().and_then(|e| e.downcast_ref())    }} impl AliasExpandError for TemplateParseError {    fn invalid_arguments(err: InvalidArguments<'_>) -> Self {        err.into()    }     fn recursive_expansion(id: AliasId<'_>, span: pest::Span<'_>) -> Self {        Self::with_span(TemplateParseErrorKind::RecursiveAlias(id.to_string()), span)    }     fn within_alias_expansion(self, id: AliasId<'_>, span: pest::Span<'_>) -> Self {        let kind = match id {            AliasId::Symbol(_) | AliasId::Function(..) => {                TemplateParseErrorKind::InAliasExpansion(id.to_string())            }            AliasId::Parameter(_) => TemplateParseErrorKind::InParameterExpansion(id.to_string()),        };        Self::with_span(kind, span).with_source(self)    }} impl From<pest::error::Error<Rule>> for TemplateParseError {    fn from(err: pest::error::Error<Rule>) -> Self {        TemplateParseError {            kind: TemplateParseErrorKind::SyntaxError,            pest_error: Box::new(rename_rules_in_pest_error(err)),            source: None,        }    }} impl From<InvalidArguments<'_>> for TemplateParseError {    fn from(err: InvalidArguments<'_>) -> Self {        let kind = TemplateParseErrorKind::InvalidArguments {            name: err.name.to_owned(),            message: err.message,        };        Self::with_span(kind, err.span)    }} fn rename_rules_in_pest_error(err: pest::error::Error<Rule>) -> pest::error::Error<Rule> {    err.renamed_rules(|rule| {        rule.to_symbol()            .map(|sym| format!("`{sym}`"))            .unwrap_or_else(|| format!("<{rule:?}>"))    })} #[derive(Clone, Debug, PartialEq)]pub enum ExpressionKind<'i> {    Identifier(&'i str),    Boolean(bool),    Integer(i64),    String(String),    Unary(UnaryOp, Box<ExpressionNode<'i>>),    Binary(BinaryOp, Box<ExpressionNode<'i>>, Box<ExpressionNode<'i>>),    Concat(Vec<ExpressionNode<'i>>),    FunctionCall(Box<FunctionCallNode<'i>>),    MethodCall(Box<MethodCallNode<'i>>),    Lambda(Box<LambdaNode<'i>>),    /// Identity node to preserve the span in the source template text.    AliasExpanded(AliasId<'i>, Box<ExpressionNode<'i>>),} impl<'i> FoldableExpression<'i> for ExpressionKind<'i> {    fn fold<F>(self, folder: &mut F, span: pest::Span<'i>) -> Result<Self, F::Error>    where        F: ExpressionFolder<'i, Self> + ?Sized,    {        match self {            ExpressionKind::Identifier(name) => folder.fold_identifier(name, span),            ExpressionKind::Boolean(_) | ExpressionKind::Integer(_) | ExpressionKind::String(_) => {                Ok(self)            }            ExpressionKind::Unary(op, arg) => {                let arg = Box::new(folder.fold_expression(*arg)?);                Ok(ExpressionKind::Unary(op, arg))            }            ExpressionKind::Binary(op, lhs, rhs) => {                let lhs = Box::new(folder.fold_expression(*lhs)?);                let rhs = Box::new(folder.fold_expression(*rhs)?);                Ok(ExpressionKind::Binary(op, lhs, rhs))            }            ExpressionKind::Concat(nodes) => Ok(ExpressionKind::Concat(                dsl_util::fold_expression_nodes(folder, nodes)?,            )),            ExpressionKind::FunctionCall(function) => folder.fold_function_call(function, span),            ExpressionKind::MethodCall(method) => {                // Method call is syntactically different from function call.                let method = Box::new(MethodCallNode {                    object: folder.fold_expression(method.object)?,                    function: dsl_util::fold_function_call_args(folder, method.function)?,                });                Ok(ExpressionKind::MethodCall(method))            }            ExpressionKind::Lambda(lambda) => {                let lambda = Box::new(LambdaNode {                    params: lambda.params,                    params_span: lambda.params_span,                    body: folder.fold_expression(lambda.body)?,                });                Ok(ExpressionKind::Lambda(lambda))            }            ExpressionKind::AliasExpanded(id, subst) => {                let subst = Box::new(folder.fold_expression(*subst)?);                Ok(ExpressionKind::AliasExpanded(id, subst))            }        }    }} impl<'i> AliasExpandableExpression<'i> for ExpressionKind<'i> {    fn identifier(name: &'i str) -> Self {        ExpressionKind::Identifier(name)    }     fn function_call(function: Box<FunctionCallNode<'i>>) -> Self {        ExpressionKind::FunctionCall(function)    }     fn alias_expanded(id: AliasId<'i>, subst: Box<ExpressionNode<'i>>) -> Self {        ExpressionKind::AliasExpanded(id, subst)    }} #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]pub enum UnaryOp {    /// `!`    LogicalNot,    /// `-`    Negate,} #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]pub enum BinaryOp {    /// `||`    LogicalOr,    /// `&&`    LogicalAnd,    /// `==`    Eq,    /// `!=`    Ne,    /// `>=`    Ge,    /// `>`    Gt,    /// `<=`    Le,    /// `<`    Lt,} pub type ExpressionNode<'i> = dsl_util::ExpressionNode<'i, ExpressionKind<'i>>;pub type FunctionCallNode<'i> = dsl_util::FunctionCallNode<'i, ExpressionKind<'i>>; #[derive(Clone, Debug, PartialEq)]pub struct MethodCallNode<'i> {    pub object: ExpressionNode<'i>,    pub function: FunctionCallNode<'i>,} #[derive(Clone, Debug, PartialEq)]pub struct LambdaNode<'i> {    pub params: Vec<&'i str>,    pub params_span: pest::Span<'i>,    pub body: ExpressionNode<'i>,} fn parse_identifier_or_literal(pair: Pair<Rule>) -> ExpressionKind {    assert_eq!(pair.as_rule(), Rule::identifier);    match pair.as_str() {        "false" => ExpressionKind::Boolean(false),        "true" => ExpressionKind::Boolean(true),        name => ExpressionKind::Identifier(name),    }} fn parse_identifier_name(pair: Pair<Rule>) -> TemplateParseResult<&str> {    let span = pair.as_span();    if let ExpressionKind::Identifier(name) = parse_identifier_or_literal(pair) {        Ok(name)    } else {        Err(TemplateParseError::expression("Expected identifier", span))    }} 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();    let params: Vec<_> = params_pair        .into_inner()        .map(parse_identifier_name)        .try_collect()?;    if params.iter().all_unique() {        Ok(params)    } else {        Err(TemplateParseError::with_span(            TemplateParseErrorKind::RedefinedFunctionParameter,            params_span,        ))    }} fn parse_lambda_node(pair: Pair<Rule>) -> TemplateParseResult<LambdaNode> {    assert_eq!(pair.as_rule(), Rule::lambda);    let mut inner = pair.into_inner();    let params_pair = inner.next().unwrap();    let params_span = params_pair.as_span();    let body_pair = inner.next().unwrap();    let params = parse_formal_parameters(params_pair)?;    let body = parse_template_node(body_pair)?;    Ok(LambdaNode {        params,        params_span,        body,    })} fn parse_term_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {    assert_eq!(pair.as_rule(), Rule::term);    let mut inner = pair.into_inner();    let expr = inner.next().unwrap();    let span = expr.as_span();    let primary = match expr.as_rule() {        Rule::string_literal => {            let text = STRING_LITERAL_PARSER.parse(expr.into_inner());            ExpressionNode::new(ExpressionKind::String(text), span)        }        Rule::raw_string_literal => {            let [content] = expr.into_inner().collect_array().unwrap();            assert_eq!(content.as_rule(), Rule::raw_string_content);            let text = content.as_str().to_owned();            ExpressionNode::new(ExpressionKind::String(text), span)        }        Rule::integer_literal => {            let value = expr.as_str().parse().map_err(|err| {                TemplateParseError::expression("Invalid integer literal", span).with_source(err)            })?;            ExpressionNode::new(ExpressionKind::Integer(value), span)        }        Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span),        Rule::function => {            let function = Box::new(FUNCTION_CALL_PARSER.parse(                expr,                parse_identifier_name,                parse_template_node,            )?);            ExpressionNode::new(ExpressionKind::FunctionCall(function), span)        }        Rule::lambda => {            let lambda = Box::new(parse_lambda_node(expr)?);            ExpressionNode::new(ExpressionKind::Lambda(lambda), span)        }        Rule::template => parse_template_node(expr)?,        other => panic!("unexpected term: {other:?}"),    };

Lines 1–500 of 1350.