luau-syntax 0.732.0

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

impl<'source, 'ast, 'name, 'names> Parser<'source, 'ast, 'name, 'names>
where
    'name: 'ast,
{
    pub(in crate::parser) fn parse_optional_generic_parameters(
        &mut self,
        with_default_values: bool,
    ) -> Result<ParsedGenericParameters<'ast>> {
        if self.current.kind() == TokenKind::Less {
            if self.cst.enabled() {
                self.parse_generic_parameters_with_cst(with_default_values)
            } else {
                self.parse_generic_parameters(with_default_values)
            }
        } else {
            Ok(ParsedGenericParameters::default())
        }
    }

    pub(in crate::parser) fn parse_generic_parameters_with_cst(
        &mut self,
        with_default_values: bool,
    ) -> Result<ParsedGenericParameters<'ast>> {
        let less_location = self.current_location();
        let open = self.current_position();
        let mut commas = self.temp_positions();
        self.expect_and_consume(Token::Less, "generic parameters");
        let mut seen_pack = false;
        let mut seen_default = false;
        let mut types = self.temp_generic_types();
        let mut type_packs = self.temp_generic_type_packs();

        loop {
            let name_location = self.current_token_location();
            let name = if let Token::Ident(name) = self.current {
                self.advance();
                name
            } else {
                self.report_parse_error(self.generic_parameter_name_error());
                self.name_error
            };

            let is_pack = self.current.kind() == TokenKind::Ellipsis;
            if is_pack || seen_pack {
                let mut ellipsis = Position::missing();
                if !is_pack {
                    self.report_parse_error(
                        self.located("Generic types come before generic type packs"),
                    );
                } else {
                    ellipsis = self.current_position();
                    self.advance();
                }
                seen_pack = true;

                let mut default_equals = None;
                let default_value =
                    if with_default_values && self.current.kind() == TokenKind::Equal {
                        seen_default = true;
                        let equals = self.current_position();
                        default_equals = Some(equals);
                        self.advance();
                        self.parse_generic_type_pack_default()?
                    } else if seen_default {
                        self.report_parse_error(
                            self.located("Expected default type pack after type pack name"),
                        );
                        None
                    } else {
                        None
                    };

                type_packs.push_back(self.alloc_generic_type_pack_with_cst(
                    GenericTypePack {
                        location: name_location,
                        name,
                        default_value,
                    },
                    self.cst_node(|| {
                        CstNode::GenericTypePack(CstGenericTypePack {
                            ellipsis,
                            default_equals,
                        })
                    }),
                ));
            } else if with_default_values && self.current.kind() == TokenKind::Equal {
                seen_default = true;
                let equals = self.current_position();
                self.advance();
                let default_value = self.parse_type_annotation()?;
                types.push_back(self.alloc_generic_type_with_cst(
                    GenericType {
                        location: name_location,
                        name,
                        default_value: Some(default_value),
                    },
                    self.cst_node(|| {
                        CstNode::GenericType(CstGenericType {
                            default_equals: Some(equals),
                        })
                    }),
                ));
            } else if seen_default {
                self.report_parse_error(self.located("Expected default type after type name"));
                types.push_back(self.alloc_generic_type_with_cst(
                    GenericType {
                        location: name_location,
                        name,
                        default_value: None,
                    },
                    self.cst_node(|| {
                        CstNode::GenericType(CstGenericType {
                            default_equals: None,
                        })
                    }),
                ));
            } else {
                types.push_back(self.alloc_generic_type_with_cst(
                    GenericType {
                        location: name_location,
                        name,
                        default_value: None,
                    },
                    self.cst_node(|| {
                        CstNode::GenericType(CstGenericType {
                            default_equals: None,
                        })
                    }),
                ));
            }

            match self.current {
                Token::Comma => {
                    commas.push_back(self.current_position());
                    self.advance();
                    if self.current.kind() == TokenKind::Greater {
                        self.report_parse_error(
                            self.located("Expected type after ',' but got '>' instead"),
                        );
                        let close = self.current_position();
                        self.advance();
                        return Ok(ParsedGenericParameters {
                            types: types.as_slice().to_vec(),
                            type_packs: type_packs.as_slice().to_vec(),
                            open,
                            commas: commas.as_slice().to_vec(),
                            close,
                        });
                    }
                }
                Token::Greater => {
                    let close = self.current_position();
                    self.advance();
                    return Ok(ParsedGenericParameters {
                        types: types.as_slice().to_vec(),
                        type_packs: type_packs.as_slice().to_vec(),
                        open,
                        commas: commas.as_slice().to_vec(),
                        close,
                    });
                }
                _ => {
                    let close = if self.expect_match_token(
                        Token::Greater,
                        ">",
                        "<",
                        less_location,
                        false,
                    ) {
                        self.previous_token_location().begin
                    } else {
                        Position::missing()
                    };
                    return Ok(ParsedGenericParameters {
                        types: types.as_slice().to_vec(),
                        type_packs: type_packs.as_slice().to_vec(),
                        open,
                        commas: commas.as_slice().to_vec(),
                        close,
                    });
                }
            }
        }
    }

    pub(in crate::parser) fn parse_generic_parameters(
        &mut self,
        with_default_values: bool,
    ) -> Result<ParsedGenericParameters<'ast>> {
        let less_location = self.current_location();
        self.expect_and_consume(Token::Less, "generic parameters");
        let mut seen_pack = false;
        let mut seen_default = false;
        let mut types = self.temp_generic_types();
        let mut type_packs = self.temp_generic_type_packs();

        loop {
            let name_location = self.current_token_location();
            let name = if let Token::Ident(name) = self.current {
                self.advance();
                name
            } else {
                self.report_parse_error(self.generic_parameter_name_error());
                self.name_error
            };

            let is_pack = self.current.kind() == TokenKind::Ellipsis;
            if is_pack || seen_pack {
                if !is_pack {
                    self.report_parse_error(
                        self.located("Generic types come before generic type packs"),
                    );
                } else {
                    self.advance();
                }
                seen_pack = true;

                let default_value =
                    if with_default_values && self.current.kind() == TokenKind::Equal {
                        seen_default = true;
                        self.advance();
                        self.parse_generic_type_pack_default()?
                    } else if seen_default {
                        self.report_parse_error(
                            self.located("Expected default type pack after type pack name"),
                        );
                        None
                    } else {
                        None
                    };

                type_packs.push_back(self.alloc_generic_type_pack_with_cst(
                    GenericTypePack {
                        location: name_location,
                        name,
                        default_value,
                    },
                    None,
                ));
            } else if with_default_values && self.current.kind() == TokenKind::Equal {
                seen_default = true;
                self.advance();
                let default_value = self.parse_type_annotation()?;
                types.push_back(self.alloc_generic_type_with_cst(
                    GenericType {
                        location: name_location,
                        name,
                        default_value: Some(default_value),
                    },
                    None,
                ));
            } else if seen_default {
                self.report_parse_error(self.located("Expected default type after type name"));
                types.push_back(self.alloc_generic_type_with_cst(
                    GenericType {
                        location: name_location,
                        name,
                        default_value: None,
                    },
                    None,
                ));
            } else {
                types.push_back(self.alloc_generic_type_with_cst(
                    GenericType {
                        location: name_location,
                        name,
                        default_value: None,
                    },
                    None,
                ));
            }

            match self.current {
                Token::Comma => {
                    self.advance();
                    if self.current.kind() == TokenKind::Greater {
                        self.report_parse_error(
                            self.located("Expected type after ',' but got '>' instead"),
                        );
                        self.advance();
                        return Ok(ParsedGenericParameters {
                            types: types.as_slice().to_vec(),
                            type_packs: type_packs.as_slice().to_vec(),
                            open: Position::missing(),
                            commas: Vec::new(),
                            close: Position::missing(),
                        });
                    }
                }
                Token::Greater => {
                    self.advance();
                    return Ok(ParsedGenericParameters {
                        types: types.as_slice().to_vec(),
                        type_packs: type_packs.as_slice().to_vec(),
                        open: Position::missing(),
                        commas: Vec::new(),
                        close: Position::missing(),
                    });
                }
                _ => {
                    self.expect_match_token(Token::Greater, ">", "<", less_location, false);
                    return Ok(ParsedGenericParameters {
                        types: types.as_slice().to_vec(),
                        type_packs: type_packs.as_slice().to_vec(),
                        open: Position::missing(),
                        commas: Vec::new(),
                        close: Position::missing(),
                    });
                }
            }
        }
    }

    pub(in crate::parser) fn parse_generic_type_pack_default(
        &mut self,
    ) -> Result<Option<TypePack<'ast>>> {
        let ident_starts_type_pack =
            matches!(self.current, Token::Ident(_)) && self.peek().kind() == TokenKind::Ellipsis;
        match self.current {
            Token::Ellipsis => {
                let annotation = self.parse_type_pack()?;
                Ok(Some(annotation))
            }
            Token::Ident(_) if ident_starts_type_pack => {
                let annotation = self.parse_type_pack()?;
                Ok(Some(annotation))
            }
            Token::Greater => {
                let start = self.previous_token_end_position();
                self.report_parse_error(self.error_at(
                    Location::new(start, self.current_token_location().end),
                    "Expected type, got '>'",
                ));
                let message_index = self.report_parse_error(self.error_at(
                    Location::new(start, self.current_position()),
                    "Expected type pack after '=', got type",
                ));
                let _ = message_index;
                Ok(None)
            }
            _ => match self.parse_simple_type_or_pack()? {
                TypeOrPack::Pack(pack) => Ok(Some(pack)),
                TypeOrPack::Type(annotation) => {
                    self.report_parse_error(self.error_at(
                        annotation.location,
                        "Expected type pack after '=', got type",
                    ));
                    Ok(None)
                }
            },
        }
    }

    pub(in crate::parser) fn parse_explicit_type_instantiation(
        &mut self,
    ) -> Result<ExplicitTypeInstantiation<'ast>> {
        let begin = self.current_token_location();
        let mut instantiation = self.cst.enabled().then(|| CstTypeInstantiation {
            left_arrow_1: self.current_position(),
            ..CstTypeInstantiation::default()
        });
        self.advance();

        let TypeParameters {
            arguments,
            open,
            commas,
            close,
        } = self.parse_type_parameters_with_cst()?;
        let end_location = self.current_token_location();
        if let Some(instantiation) = &mut instantiation {
            instantiation.left_arrow_2 = open;
            instantiation.comma_positions = commas;
            instantiation.right_arrow_1 = close;
            if self.current.kind() == TokenKind::Greater {
                instantiation.right_arrow_2 = self.current_position();
            }
        }
        self.expect_match_token(Token::Greater, ">", "<", begin, false);
        Ok(ExplicitTypeInstantiation {
            arguments,
            cst: instantiation,
            end_location,
        })
    }
}

pub(in crate::parser) struct ExplicitTypeInstantiation<'ast> {
    pub(in crate::parser) arguments: Vec<TypeOrPack<'ast>>,
    pub(in crate::parser) cst: Option<CstTypeInstantiation>,
    pub(in crate::parser) end_location: Location,
}