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 located<M: Into<ParseMessage>>(&self, message: M) -> ParseError {
        self.error_at(self.current_location(), message)
    }

    pub(in crate::parser) fn error_at<M: Into<ParseMessage>>(
        &self,
        location: Location,
        message: M,
    ) -> ParseError {
        ParseError::new(location, message)
    }

    pub(in crate::parser) fn unexpected(&self, expected: &'static str) -> ParseError {
        if let Some(found) = self.current.description() {
            self.located(format!("Expected {expected}, got {found}"))
        } else {
            self.located(format!(
                "expected {expected}, found {}",
                self.current.name()
            ))
        }
    }

    pub(in crate::parser) fn interpolated_double_brace_error(&self) -> ParseError {
        self.located(
            "Double braces are not permitted within interpolated strings; did you mean '\\{'?",
        )
    }

    pub(in crate::parser) fn interpolated_missing_expression_error(&self) -> ParseError {
        self.located("Malformed interpolated string, expected expression inside '{}'")
    }

    pub(in crate::parser) fn interpolated_malformed_escape_error(&self) -> ParseError {
        self.located("Interpolated string literal contains malformed escape sequence")
    }

    pub(in crate::parser) fn interpolated_string_as_type_error(
        &self,
        location: Location,
    ) -> ParseError {
        self.error_at(
            location,
            "Interpolated string literals cannot be used as types",
        )
    }

    pub(in crate::parser) fn unmatched_group_error(&self, location: Location) -> ParseError {
        let position = if self.current_position().line == location.begin.line {
            format!("column {}", location.begin.column + 1)
        } else {
            format!("line {}", location.begin.line + 1)
        };
        let suggestion = if self.current.kind() == TokenKind::Equal {
            "; did you mean to use '{' when defining a table?"
        } else {
            ""
        };

        self.located(format!(
            "Expected ')' (to close '(' at {position}), got {}{suggestion}",
            self.current
        ))
    }

    pub(in crate::parser) fn method_call_arguments_error(
        &self,
        function_location: Location,
        function_end_line: usize,
    ) -> ParseError {
        if self.current_line() > function_end_line {
            self.error_at(
                function_location,
                "Expected function call arguments after '('",
            )
        } else {
            self.error_at(
                Location::new(function_location.begin, self.current_position()),
                format!(
                    "Expected '(', '{{' or <string> when parsing function call, got {}",
                    self.current
                ),
            )
        }
    }

    pub(in crate::parser) fn function_type_arrow_error(&self) -> ParseError {
        let got = &self.current;
        self.located(format!(
            "Expected '->' when parsing function type, got {got}"
        ))
    }

    pub(in crate::parser) fn empty_function_type_arrow_error(
        &self,
        location: Location,
    ) -> ParseError {
        self.error_at(
            location,
            "Expected '->' after '()' when parsing function type; did you mean 'nil'?",
        )
    }

    pub(in crate::parser) fn function_type_colon_return_error(&self) -> ParseError {
        self.located(
            "Return types in function type annotations are written after '->' instead of ':'",
        )
    }

    pub(in crate::parser) fn function_return_arrow_error(&self) -> ParseError {
        self.located("Function return type annotations are written after ':' instead of '->'")
    }

    pub(in crate::parser) fn table_field_name_error(&self) -> ParseError {
        self.located(format!(
            "Expected identifier when parsing table field, got {}",
            self.current
        ))
    }

    pub(in crate::parser) fn type_name_error(&self) -> ParseError {
        self.located(format!(
            "Expected identifier when parsing type name, got {}",
            self.current
        ))
    }

    pub(in crate::parser) fn missing_type_parse_error(&self) -> ParseError {
        let location = Location::new(
            self.previous_token_end_position(),
            self.current_token_location().end,
        );
        self.error_at(location, format!("Expected type, got {}", self.current))
    }

    pub(in crate::parser) fn generic_parameter_name_error(&self) -> ParseError {
        self.located(format!("Expected identifier, got {}", self.current))
    }

    pub(in crate::parser) fn identifier_error(&self, context: Option<&'static str>) -> ParseError {
        let got = self
            .current
            .description()
            .map(|description| description.to_string())
            .unwrap_or_else(|| self.current.to_string());
        let message = if let Some(context) = context {
            format!("Expected identifier when parsing {context}, got {got}")
        } else {
            format!("Expected identifier, got {got}")
        };
        self.located(message)
    }

    pub(in crate::parser) fn expected_eof_error(&self) -> ParseError {
        self.located(format!("Expected <eof>, got {}", self.current))
    }

    pub(in crate::parser) fn variable_name_error(&self) -> ParseError {
        let got = self
            .current
            .description()
            .map(|description| description.to_string())
            .unwrap_or_else(|| self.current.to_string());
        self.located(format!(
            "Expected identifier when parsing variable name, got {got}"
        ))
    }

    pub(in crate::parser) fn property_name_error(&self) -> ParseError {
        self.located(format!(
            "Expected identifier when parsing property name, got {}",
            self.current
        ))
    }

    pub(in crate::parser) fn attribute_name_error(&self) -> ParseError {
        self.located(format!(
            "Expected identifier when parsing attribute name, got {}",
            self.current
        ))
    }

    pub(in crate::parser) fn attribute_statement_error(&self) -> ParseError {
        let expected = "'function', 'local function', 'const function', 'declare function' or a function type declaration";
        self.located(format!(
            "Expected {expected} after attribute, but got {} instead",
            self.current
        ))
    }

    pub(in crate::parser) fn attribute_expression_error(&self, location: Location) -> ParseError {
        self.error_at(
            location,
            format!(
                "Expected 'function' declaration after attribute, but got {} instead",
                self.current
            ),
        )
    }

    pub(in crate::parser) fn matched_token_error(
        &self,
        expected: &'static str,
        opener: &'static str,
        location: Location,
    ) -> ParseError {
        let position = if self.current_position().line == location.begin.line {
            format!("column {}", location.begin.column + 1)
        } else {
            format!("line {}", location.begin.line + 1)
        };
        let got = &self.current;
        self.located(format!(
            "Expected '{expected}' (to close '{opener}' at {position}), got {got}"
        ))
    }

    pub(in crate::parser) fn matched_block_token_error(
        &self,
        expected: &'static str,
        opener: &'static str,
        location: Location,
    ) -> ParseError {
        let position = if self.current_position().line == location.begin.line {
            format!("column {}", location.begin.column + 1)
        } else {
            format!("line {}", location.begin.line + 1)
        };
        let got = &self.current;
        let mut message =
            format!("Expected '{expected}' (to close '{opener}' at {position}), got {got}");

        if let Some(suspect) = self.contexts.end_mismatch_suspect
            && suspect.line > location.begin.line as usize + 1
        {
            message.push_str(&format!(
                "; did you forget to close '{}' at line {}?",
                suspect.opener, suspect.line
            ));
        }

        self.located(message)
    }

    pub(in crate::parser) fn loop_control_error(
        &self,
        location: Location,
        keyword: &'static str,
    ) -> ParseError {
        self.error_at(
            location,
            format!("{keyword} statement must be inside a loop"),
        )
    }

    pub(in crate::parser) fn varargs_error(&self) -> ParseError {
        self.located("Cannot use '...' outside of a vararg function")
    }

    pub(in crate::parser) fn malformed_string_error(&self) -> ParseError {
        self.located("Malformed string; did you forget to finish it?")
    }
}