luau-syntax 0.732.0

Luau lexer, parser, AST, CST, and source utilities
Documentation
use super::*;

impl<'source, 'ast, 'name, 'names> Parser<'source, 'ast, 'name, 'names>
where
    'name: 'ast,
{
    pub(in crate::parser) fn parse_interpolated_string(
        &mut self,
        first: &'source [u8],
    ) -> Result<Expression<'ast>> {
        let start_location = self.current_token_location();
        let mut end_location = start_location;
        let mut recovery_error = None;
        let mut strings = self.temp_strings();
        let mut args = self.temp_expressions();
        let mut interp_cst = self
            .cst
            .enabled()
            .then(|| (self.temp_source_strings(), self.temp_positions()));
        if let Some((source_strings, string_positions)) = &mut interp_cst {
            source_strings.push_back(self.current_source_string());
            string_positions.push_back(self.current_position());
        }
        let first_string = match self.parse_interpolated_literal(first) {
            Ok(value) => value,
            Err(error) => {
                self.advance();
                let message_index = self.report_parse_error(ParseError::new(
                    Location::new(start_location.begin, end_location.end),
                    error.message,
                ));
                return Ok(self.alloc_expression(ExpressionInit::new(
                    Location::new(start_location.begin, end_location.end),
                    ExpressionKind::Error {
                        expressions: self.empty_expression_slice(),
                        message_index,
                    },
                )));
            }
        };
        strings.push_back(first_string);
        self.advance();

        loop {
            if matches!(
                self.current,
                Token::InterpStringMid(_) | Token::InterpStringEnd(_)
            ) {
                let message_index =
                    self.report_parse_error(self.interpolated_missing_expression_error());
                self.advance();
                let expressions = self.empty_expression_slice();
                args.push_back(self.alloc_expression(ExpressionInit::new(
                    end_location,
                    ExpressionKind::Error {
                        expressions,
                        message_index,
                    },
                )));
                break;
            }
            if matches!(self.current, Token::BrokenString) {
                self.advance();
                let message_index = self.report_parse_error(self.error_at(
                    end_location,
                    "Malformed interpolated string; did you forget to add a '`'?",
                ));
                let expressions = self.empty_expression_slice();
                args.push_back(self.alloc_expression(ExpressionInit::new(
                    end_location,
                    ExpressionKind::Error {
                        expressions,
                        message_index,
                    },
                )));
                break;
            }
            let expression = self.parse_expression()?;
            args.push_back(expression);

            match self.current {
                Token::InterpStringMid(value) => {
                    let location = self.current_token_location();
                    end_location = location;
                    if let Some((source_strings, string_positions)) = &mut interp_cst {
                        source_strings.push_back(self.current_source_string());
                        string_positions.push_back(self.current_position());
                    }
                    let string = match self.parse_interpolated_literal(value) {
                        Ok(value) => value,
                        Err(error) => {
                            self.advance();
                            let location = Location::new(start_location.begin, end_location.end);
                            let message_index =
                                self.report_parse_error(ParseError::new(location, error.message));
                            return Ok(self.alloc_expression(ExpressionInit::new(
                                location,
                                ExpressionKind::Error {
                                    expressions: self.empty_expression_slice(),
                                    message_index,
                                },
                            )));
                        }
                    };
                    strings.push_back(string);
                    self.advance();
                }
                Token::InterpStringEnd(value) => {
                    let location = self.current_token_location();
                    end_location = location;
                    if let Some((source_strings, string_positions)) = &mut interp_cst {
                        source_strings.push_back(self.current_source_string());
                        string_positions.push_back(self.current_position());
                    }
                    let string = match self.parse_interpolated_literal(value) {
                        Ok(value) => value,
                        Err(error) => {
                            self.advance();
                            let location = Location::new(start_location.begin, end_location.end);
                            let message_index =
                                self.report_parse_error(ParseError::new(location, error.message));
                            return Ok(self.alloc_expression(ExpressionInit::new(
                                location,
                                ExpressionKind::Error {
                                    expressions: self.empty_expression_slice(),
                                    message_index,
                                },
                            )));
                        }
                    };
                    strings.push_back(string);
                    self.advance();
                    break;
                }
                Token::BrokenInterpDoubleBrace(_) => {
                    self.advance();
                    let message_index = self.report_parse_error(self.error_at(
                        end_location,
                        "Double braces are not permitted within interpolated strings; did you mean '\\{'?"
                                ,
                    ));
                    return Ok(self.alloc_expression(ExpressionInit::new(
                        end_location,
                        ExpressionKind::Error {
                            expressions: self.empty_expression_slice(),
                            message_index,
                        },
                    )));
                }
                Token::BrokenString => {
                    self.advance();
                    recovery_error = Some(if self.lexer.interpolation_brace_is_open() {
                        "Malformed interpolated string; did you forget to add a '}'?"
                    } else {
                        "Malformed interpolated string; did you forget to add a '`'?"
                    });
                    break;
                }
                Token::Eof => {
                    recovery_error = Some(if self.lexer.interpolation_brace_is_open() {
                        "Malformed interpolated string; did you forget to add a '}'?"
                    } else {
                        "Malformed interpolated string; did you forget to add a '`'?"
                    });
                    break;
                }
                _ => {
                    let message_index = self.report_parse_error(self.error_at(
                        end_location,
                        format!("Malformed interpolated string, got {}", self.current),
                    ));
                    return Ok(self.alloc_expression(ExpressionInit::new(
                        end_location,
                        ExpressionKind::Error {
                            expressions: self.empty_expression_slice(),
                            message_index,
                        },
                    )));
                }
            }
        }

        let end = if recovery_error.is_some() {
            self.previous_token_location().end
        } else {
            end_location.end
        };
        let location = Location::new(start_location.begin, end);
        let expression = self.alloc_expression_with_cst(
            ExpressionInit::new(
                location,
                ExpressionKind::InterpString {
                    strings: self.arena.alloc_slice_copy(strings.as_slice()),
                    expressions: self.arena.alloc_slice_copy(args.as_slice()),
                },
            ),
            interp_cst.map(|(source_strings, string_positions)| {
                CstNode::ExprInterpString(CstExprInterpString {
                    source_strings: source_strings.as_slice().to_vec(),
                    string_positions: string_positions.as_slice().to_vec(),
                })
            }),
        );

        if let Some(message) = recovery_error {
            self.report_parse_error(self.error_at(self.previous_token_location(), message));
        }

        Ok(expression)
    }

    pub(in crate::parser) fn parse_quoted_string(
        &mut self,
        value: &[u8],
        location: Location,
        quote_style: StringQuoteStyle,
    ) -> Expression<'ast> {
        let Some(value) = fixup_string_bytes(value) else {
            let message_index = self.report_parse_error(self.error_at(
                location,
                "String literal contains malformed escape sequence",
            ));
            return self.arena.alloc_expression_error_direct(
                location,
                self.empty_expression_slice(),
                message_index,
            );
        };

        self.arena
            .alloc_expression_string_direct(location, self.ast_string(&value), quote_style)
    }
}