Zachary DremannAllow \0 escape for nulls2177dc03 years agoHistory
1217 lines · 41.9 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::num::ParseIntError;use std::{error, fmt}; use itertools::Itertools as _;use pest::iterators::{Pair, Pairs};use pest::Parser;use pest_derive::Parser;use thiserror::Error; #[derive(Parser)]#[grammar = "template.pest"]struct TemplateParser; pub type TemplateParseResult<T> = Result<T, TemplateParseError>; #[derive(Clone, Debug)]pub struct TemplateParseError {    kind: TemplateParseErrorKind,    pest_error: Box<pest::error::Error<Rule>>,    origin: Option<Box<TemplateParseError>>,} #[derive(Clone, Debug, Eq, Error, PartialEq)]pub enum TemplateParseErrorKind {    #[error("Syntax error")]    SyntaxError,    #[error("Invalid integer literal: {0}")]    ParseIntError(#[source] ParseIntError),    #[error(r#"Keyword "{0}" doesn't exist"#)]    NoSuchKeyword(String),    #[error(r#"Function "{0}" doesn't exist"#)]    NoSuchFunction(String),    #[error(r#"Method "{name}" doesn't exist for type "{type_name}""#)]    NoSuchMethod { type_name: String, name: String },    #[error(r#"Function "{name}": {message}"#)]    InvalidArguments { name: String, message: String },    #[error("Redefinition of function parameter")]    RedefinedFunctionParameter,    #[error("{0}")]    UnexpectedExpression(String),    #[error(r#"Alias "{0}" cannot be expanded"#)]    BadAliasExpansion(String),    #[error(r#"Alias "{0}" expanded recursively"#)]    RecursiveAlias(String),} impl TemplateParseError {    pub fn with_span(kind: TemplateParseErrorKind, span: pest::Span<'_>) -> Self {        let pest_error = Box::new(pest::error::Error::new_from_span(            pest::error::ErrorVariant::CustomError {                message: kind.to_string(),            },            span,        ));        TemplateParseError {            kind,            pest_error,            origin: None,        }    }     pub fn with_span_and_origin(        kind: TemplateParseErrorKind,        span: pest::Span<'_>,        origin: Self,    ) -> Self {        let pest_error = Box::new(pest::error::Error::new_from_span(            pest::error::ErrorVariant::CustomError {                message: kind.to_string(),            },            span,        ));        TemplateParseError {            kind,            pest_error,            origin: Some(Box::new(origin)),        }    }     pub fn no_such_keyword(name: impl Into<String>, span: pest::Span<'_>) -> Self {        TemplateParseError::with_span(TemplateParseErrorKind::NoSuchKeyword(name.into()), span)    }     pub fn no_such_function(function: &FunctionCallNode) -> Self {        TemplateParseError::with_span(            TemplateParseErrorKind::NoSuchFunction(function.name.to_owned()),            function.name_span,        )    }     pub 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(),            },            function.name_span,        )    }     pub fn invalid_arguments(function: &FunctionCallNode, message: impl Into<String>) -> Self {        TemplateParseError::with_span(            TemplateParseErrorKind::InvalidArguments {                name: function.name.to_owned(),                message: message.into(),            },            function.args_span,        )    }     pub fn expected_type(type_name: &str, span: pest::Span<'_>) -> Self {        let message = format!(r#"Expected expression of type "{type_name}""#);        TemplateParseError::unexpected_expression(message, span)    }     pub fn unexpected_expression(message: impl Into<String>, span: pest::Span<'_>) -> Self {        TemplateParseError::with_span(            TemplateParseErrorKind::UnexpectedExpression(message.into()),            span,        )    }     pub fn within_alias_expansion(self, id: TemplateAliasId<'_>, span: pest::Span<'_>) -> Self {        TemplateParseError::with_span_and_origin(            TemplateParseErrorKind::BadAliasExpansion(id.to_string()),            span,            self,        )    }     /// Original parsing error which typically occurred in an alias expression.    pub fn origin(&self) -> Option<&Self> {        self.origin.as_deref()    }} impl From<pest::error::Error<Rule>> for TemplateParseError {    fn from(err: pest::error::Error<Rule>) -> Self {        TemplateParseError {            kind: TemplateParseErrorKind::SyntaxError,            pest_error: Box::new(err),            origin: None,        }    }} impl fmt::Display for TemplateParseError {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        self.pest_error.fmt(f)    }} impl error::Error for TemplateParseError {    fn source(&self) -> Option<&(dyn error::Error + 'static)> {        if let Some(e) = self.origin() {            return Some(e as &dyn error::Error);        }        match &self.kind {            // SyntaxError is a wrapper for pest::error::Error.            TemplateParseErrorKind::SyntaxError => Some(&self.pest_error as &dyn error::Error),            // Otherwise the kind represents this error.            e => e.source(),        }    }} /// AST node without type or name checking.#[derive(Clone, Debug, PartialEq)]pub struct ExpressionNode<'i> {    pub kind: ExpressionKind<'i>,    pub span: pest::Span<'i>,} impl<'i> ExpressionNode<'i> {    fn new(kind: ExpressionKind<'i>, span: pest::Span<'i>) -> Self {        ExpressionNode { kind, span }    }} #[derive(Clone, Debug, PartialEq)]pub enum ExpressionKind<'i> {    Identifier(&'i str),    Boolean(bool),    Integer(i64),    String(String),    Concat(Vec<ExpressionNode<'i>>),    FunctionCall(FunctionCallNode<'i>),    MethodCall(MethodCallNode<'i>),    Lambda(LambdaNode<'i>),    /// Identity node to preserve the span in the source template text.    AliasExpanded(TemplateAliasId<'i>, Box<ExpressionNode<'i>>),} #[derive(Clone, Debug, PartialEq)]pub struct FunctionCallNode<'i> {    pub name: &'i str,    pub name_span: pest::Span<'i>,    pub args: Vec<ExpressionNode<'i>>,    pub args_span: pest::Span<'i>,} #[derive(Clone, Debug, PartialEq)]pub struct MethodCallNode<'i> {    pub object: Box<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: Box<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::unexpected_expression(            "Expected identifier",            span,        ))    }} fn parse_string_literal(pair: Pair<Rule>) -> String {    assert_eq!(pair.as_rule(), Rule::literal);    let mut result = String::new();    for part in pair.into_inner() {        match part.as_rule() {            Rule::raw_literal => {                result.push_str(part.as_str());            }            Rule::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();    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_function_call_node(pair: Pair<Rule>) -> TemplateParseResult<FunctionCallNode> {    assert_eq!(pair.as_rule(), Rule::function);    let mut inner = pair.into_inner();    let name_pair = inner.next().unwrap();    let name_span = name_pair.as_span();    let args_pair = inner.next().unwrap();    let args_span = args_pair.as_span();    assert_eq!(args_pair.as_rule(), Rule::function_arguments);    let name = parse_identifier_name(name_pair)?;    let args = args_pair        .into_inner()        .map(parse_template_node)        .try_collect()?;    Ok(FunctionCallNode {        name,        name_span,        args,        args_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: Box::new(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::literal => {            let text = parse_string_literal(expr);            ExpressionNode::new(ExpressionKind::String(text), span)        }        Rule::integer_literal => {            let value = expr.as_str().parse().map_err(|err| {                TemplateParseError::with_span(TemplateParseErrorKind::ParseIntError(err), span)            })?;            ExpressionNode::new(ExpressionKind::Integer(value), span)        }        Rule::identifier => ExpressionNode::new(parse_identifier_or_literal(expr), span),        Rule::function => {            let function = parse_function_call_node(expr)?;            ExpressionNode::new(ExpressionKind::FunctionCall(function), span)        }        Rule::lambda => {            let lambda = parse_lambda_node(expr)?;            ExpressionNode::new(ExpressionKind::Lambda(lambda), span)        }        Rule::template => parse_template_node(expr)?,        other => panic!("unexpected term: {other:?}"),    };    inner.try_fold(primary, |object, chain| {        assert_eq!(chain.as_rule(), Rule::function);        let span = object.span.start_pos().span(&chain.as_span().end_pos());        let method = MethodCallNode {            object: Box::new(object),            function: parse_function_call_node(chain)?,        };        Ok(ExpressionNode::new(            ExpressionKind::MethodCall(method),            span,        ))    })} fn parse_template_node(pair: Pair<Rule>) -> TemplateParseResult<ExpressionNode> {    assert_eq!(pair.as_rule(), Rule::template);    let span = pair.as_span();    let inner = pair.into_inner();    let mut nodes: Vec<_> = inner.map(parse_term_node).try_collect()?;    if nodes.len() == 1 {        Ok(nodes.pop().unwrap())    } else {        Ok(ExpressionNode::new(ExpressionKind::Concat(nodes), span))    }} /// Parses text into AST nodes. No type/name checking is made at this stage.pub fn parse_template(template_text: &str) -> TemplateParseResult<ExpressionNode> {    let mut pairs: Pairs<Rule> = TemplateParser::parse(Rule::program, template_text)?;    let first_pair = pairs.next().unwrap();    if first_pair.as_rule() == Rule::EOI {        let span = first_pair.as_span();        Ok(ExpressionNode::new(ExpressionKind::Concat(vec![]), span))    } else {        parse_template_node(first_pair)    }} #[derive(Clone, Debug, Default)]pub struct TemplateAliasesMap {    symbol_aliases: HashMap<String, String>,    function_aliases: HashMap<String, (Vec<String>, String)>,} impl TemplateAliasesMap {    pub fn new() -> Self {        Self::default()    }     /// Adds new substitution rule `decl = defn`.    ///    /// Returns error if `decl` is invalid. The `defn` part isn't checked. A bad    /// `defn` will be reported when the alias is substituted.    pub fn insert(        &mut self,        decl: impl AsRef<str>,        defn: impl Into<String>,    ) -> TemplateParseResult<()> {        match TemplateAliasDeclaration::parse(decl.as_ref())? {            TemplateAliasDeclaration::Symbol(name) => {                self.symbol_aliases.insert(name, defn.into());            }            TemplateAliasDeclaration::Function(name, params) => {                self.function_aliases.insert(name, (params, defn.into()));            }        }        Ok(())    }     fn get_symbol(&self, name: &str) -> Option<(TemplateAliasId<'_>, &str)> {        self.symbol_aliases            .get_key_value(name)            .map(|(name, defn)| (TemplateAliasId::Symbol(name), defn.as_ref()))    }     fn get_function(&self, name: &str) -> Option<(TemplateAliasId<'_>, &[String], &str)> {        self.function_aliases            .get_key_value(name)            .map(|(name, (params, defn))| {                (                    TemplateAliasId::Function(name),                    params.as_ref(),                    defn.as_ref(),                )            })    }} /// Parsed declaration part of alias rule.#[derive(Clone, Debug)]enum TemplateAliasDeclaration {    Symbol(String),    Function(String, Vec<String>),} impl TemplateAliasDeclaration {    fn parse(source: &str) -> TemplateParseResult<Self> {        let mut pairs = TemplateParser::parse(Rule::alias_declaration, source)?;        let first = pairs.next().unwrap();        match first.as_rule() {            Rule::identifier => {                let name = parse_identifier_name(first)?.to_owned();                Ok(TemplateAliasDeclaration::Symbol(name))            }            Rule::function_alias_declaration => {                let mut inner = first.into_inner();                let name_pair = inner.next().unwrap();                let params_pair = inner.next().unwrap();                let name = parse_identifier_name(name_pair)?.to_owned();                let params = parse_formal_parameters(params_pair)?                    .into_iter()                    .map(|s| s.to_owned())                    .collect();                Ok(TemplateAliasDeclaration::Function(name, params))            }            r => panic!("unexpected alias declaration rule {r:?}"),        }    }} /// Borrowed reference to identify alias expression.#[derive(Clone, Copy, Debug, Eq, PartialEq)]pub enum TemplateAliasId<'a> {    Symbol(&'a str),    Function(&'a str),} impl fmt::Display for TemplateAliasId<'_> {    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {        match self {            TemplateAliasId::Symbol(name) => write!(f, "{name}"),            TemplateAliasId::Function(name) => write!(f, "{name}()"),        }    }} /// Expand aliases recursively.pub fn expand_aliases<'i>(    node: ExpressionNode<'i>,    aliases_map: &'i TemplateAliasesMap,) -> TemplateParseResult<ExpressionNode<'i>> {    #[derive(Clone, Copy, Debug)]    struct State<'a, 'i> {        aliases_map: &'i TemplateAliasesMap,        aliases_expanding: &'a [TemplateAliasId<'a>],        locals: &'a HashMap<&'a str, ExpressionNode<'i>>,

Lines 1–500 of 1217.