use std::mem;
use cairo_lang_diagnostics::DiagnosticsBuilder;
use cairo_lang_filesystem::ids::FileId;
use cairo_lang_filesystem::span::{TextOffset, TextSpan, TextWidth};
use cairo_lang_syntax as syntax;
use cairo_lang_syntax::node::ast::*;
use cairo_lang_syntax::node::db::SyntaxGroup;
use cairo_lang_syntax::node::kind::SyntaxKind;
use cairo_lang_syntax::node::{SyntaxNode, Token, TypedSyntaxNode};
use cairo_lang_utils::{extract_matches, require, LookupIntern};
use syntax::node::green::{GreenNode, GreenNodeDetails};
use syntax::node::ids::GreenId;
use crate::diagnostic::ParserDiagnosticKind;
use crate::lexer::{Lexer, LexerTerminal};
use crate::operators::{get_post_operator_precedence, get_unary_operator_precedence};
use crate::recovery::is_of_kind;
use crate::validation::{validate_literal_number, validate_short_string, validate_string};
use crate::ParserDiagnostic;
#[cfg(test)]
#[path = "parser_test.rs"]
mod test;
pub struct Parser<'a> {
db: &'a dyn SyntaxGroup,
file_id: FileId,
lexer: Lexer<'a>,
next_terminal: LexerTerminal,
pending_trivia: Vec<TriviumGreen>,
offset: TextOffset,
current_width: TextWidth,
last_trivia_length: TextWidth,
diagnostics: &'a mut DiagnosticsBuilder<ParserDiagnostic>,
pending_skipped_token_diagnostics: Vec<PendingParserDiagnostic>,
}
#[derive(PartialEq)]
pub enum TryParseFailure {
SkipToken,
DoNothing,
}
pub type TryParseResult<GreenElement> = Result<GreenElement, TryParseFailure>;
const MAX_PRECEDENCE: usize = 1000;
const MODULE_ITEM_DESCRIPTION: &str = "Const/Enum/ExternFunction/ExternType/Function/Impl/\
InlineMacro/Module/Struct/Trait/TypeAlias/Use";
const TRAIT_ITEM_DESCRIPTION: &str = "Const/Function/Impl/Type";
const IMPL_ITEM_DESCRIPTION: &str = "Const/Function/Impl/Type";
macro_rules! or_an_attribute {
($string:expr) => {
format!("{} or an attribute", $string)
};
}
impl<'a> Parser<'a> {
pub fn parse_file(
db: &'a dyn SyntaxGroup,
diagnostics: &mut DiagnosticsBuilder<ParserDiagnostic>,
file_id: FileId,
text: &'a str,
) -> SyntaxFile {
let mut lexer = Lexer::from_text(db, file_id, text);
let next_terminal = lexer.next().unwrap();
let parser = Parser {
db,
file_id,
lexer,
next_terminal,
pending_trivia: Vec::new(),
offset: Default::default(),
current_width: Default::default(),
last_trivia_length: Default::default(),
diagnostics,
pending_skipped_token_diagnostics: Default::default(),
};
let green = parser.parse_syntax_file();
SyntaxFile::from_syntax_node(db, SyntaxNode::new_root(db, file_id, green.0))
}
pub fn parse_file_expr(
db: &'a dyn SyntaxGroup,
diagnostics: &mut DiagnosticsBuilder<ParserDiagnostic>,
file_id: FileId,
text: &'a str,
) -> Expr {
let mut lexer = Lexer::from_text(db, file_id, text);
let next_terminal = lexer.next().unwrap();
let mut parser = Parser {
db,
file_id,
lexer,
next_terminal,
pending_trivia: Vec::new(),
offset: Default::default(),
current_width: Default::default(),
last_trivia_length: Default::default(),
diagnostics,
pending_skipped_token_diagnostics: Default::default(),
};
let green = parser.parse_expr();
if let Err(SkippedError(span)) = parser.skip_until(is_of_kind!()) {
parser.diagnostics.add(ParserDiagnostic {
file_id: parser.file_id,
kind: ParserDiagnosticKind::SkippedElement { element_name: "end of expr".into() },
span,
});
}
Expr::from_syntax_node(db, SyntaxNode::new_root(db, file_id, green.0))
}
fn create_and_report_missing<T: TypedSyntaxNode>(
&mut self,
missing_kind: ParserDiagnosticKind,
) -> T::Green {
let next_offset = self.offset.add_width(self.current_width - self.last_trivia_length);
self.diagnostics.add(ParserDiagnostic {
file_id: self.file_id,
kind: missing_kind,
span: TextSpan { start: next_offset, end: next_offset },
});
T::missing(self.db)
}
fn create_and_report_missing_terminal<Terminal: syntax::node::Terminal>(
&mut self,
) -> Terminal::Green {
self.create_and_report_missing::<Terminal>(ParserDiagnosticKind::MissingToken(
Terminal::KIND,
))
}
pub fn parse_syntax_file(mut self) -> SyntaxFileGreen {
let mut module_items = vec![];
if let Some(doc_item) = self.take_doc() {
module_items.push(doc_item.into());
}
module_items.extend(self.parse_attributed_list(
Self::try_parse_module_item,
is_of_kind!(),
MODULE_ITEM_DESCRIPTION,
));
let items = ModuleItemList::new_green(self.db, module_items);
assert_eq!(self.peek().kind, SyntaxKind::TerminalEndOfFile);
self.offset = self.offset.add_width(self.current_width);
let eof = self.add_trivia_to_terminal::<TerminalEndOfFile>(self.next_terminal.clone());
SyntaxFile::new_green(self.db, items, eof)
}
pub fn try_parse_module_item(&mut self) -> TryParseResult<ModuleItemGreen> {
let maybe_attributes = self.try_parse_attribute_list(MODULE_ITEM_DESCRIPTION);
let (has_attrs, attributes) = match maybe_attributes {
Ok(attributes) => (true, attributes),
Err(_) => (false, AttributeList::new_green(self.db, vec![])),
};
let post_attributes_offset = self.offset.add_width(self.current_width);
let visibility_pub = self.try_parse_visibility_pub();
let visibility = match visibility_pub {
Some(visibility) => visibility.into(),
None => VisibilityDefault::new_green(self.db).into(),
};
let post_visibility_offset = self.offset.add_width(self.current_width);
match self.peek().kind {
SyntaxKind::TerminalConst => Ok(self.expect_item_const(attributes, visibility).into()),
SyntaxKind::TerminalModule => {
Ok(self.expect_item_module(attributes, visibility).into())
}
SyntaxKind::TerminalStruct => {
Ok(self.expect_item_struct(attributes, visibility).into())
}
SyntaxKind::TerminalEnum => Ok(self.expect_item_enum(attributes, visibility).into()),
SyntaxKind::TerminalType => {
Ok(self.expect_item_type_alias(attributes, visibility).into())
}
SyntaxKind::TerminalExtern => Ok(self.expect_item_extern(attributes, visibility)),
SyntaxKind::TerminalFunction => {
Ok(self.expect_item_function_with_body(attributes, visibility).into())
}
SyntaxKind::TerminalUse => Ok(self.expect_item_use(attributes, visibility).into()),
SyntaxKind::TerminalTrait => Ok(self.expect_item_trait(attributes, visibility).into()),
SyntaxKind::TerminalImpl => Ok(self.expect_module_item_impl(attributes, visibility)),
SyntaxKind::TerminalIdentifier => {
let ident = self.take_raw();
match self.peek().kind {
SyntaxKind::TerminalNot => {
let macro_name = self.add_trivia_to_terminal::<TerminalIdentifier>(ident);
Ok(self.expect_item_inline_macro(attributes, macro_name).into())
}
SyntaxKind::TerminalLParen
| SyntaxKind::TerminalLBrace
| SyntaxKind::TerminalLBrack => {
self.diagnostics.add(ParserDiagnostic {
file_id: self.file_id,
kind: ParserDiagnosticKind::ItemInlineMacroWithoutBang {
identifier: ident.clone().text,
bracket_type: self.peek().kind,
},
span: TextSpan {
start: self.offset,
end: self.offset.add_width(self.current_width),
},
});
let macro_name = self.add_trivia_to_terminal::<TerminalIdentifier>(ident);
Ok(self
.parse_item_inline_macro_given_bang(
attributes,
macro_name,
TerminalNot::missing(self.db),
)
.into())
}
_ => {
if has_attrs {
self.skip_taken_node_with_offset(
attributes,
ParserDiagnosticKind::SkippedElement {
element_name: or_an_attribute!(MODULE_ITEM_DESCRIPTION).into(),
},
post_attributes_offset,
);
}
if let Some(visibility_pub) = visibility_pub {
self.skip_taken_node_with_offset(
visibility_pub,
ParserDiagnosticKind::SkippedElement {
element_name: or_an_attribute!(MODULE_ITEM_DESCRIPTION).into(),
},
post_visibility_offset,
);
}
self.append_skipped_token_to_pending_trivia(
ident,
ParserDiagnosticKind::SkippedElement {
element_name: or_an_attribute!(MODULE_ITEM_DESCRIPTION).into(),
},
);
Err(TryParseFailure::DoNothing)
}
}
}
_ => {
let mut result = Err(TryParseFailure::SkipToken);
if has_attrs {
self.skip_taken_node_with_offset(
attributes,
ParserDiagnosticKind::AttributesWithoutItem,
post_attributes_offset,
);
result = Ok(ModuleItem::missing(self.db));
}
if let Some(visibility_pub) = visibility_pub {
self.skip_taken_node_with_offset(
visibility_pub,
ParserDiagnosticKind::VisibilityWithoutItem,
post_visibility_offset,
);
result = Ok(ModuleItem::missing(self.db));
}
result
}
}
}
fn expect_item_module(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ItemModuleGreen {
let module_kw = self.take::<TerminalModule>();
let name = self.parse_identifier();
let body = match self.peek().kind {
SyntaxKind::TerminalLBrace => {
let lbrace = self.take::<TerminalLBrace>();
let mut module_items = vec![];
if let Some(doc_item) = self.take_doc() {
module_items.push(doc_item.into());
}
module_items.extend(self.parse_attributed_list(
Self::try_parse_module_item,
is_of_kind!(rbrace),
MODULE_ITEM_DESCRIPTION,
));
let items = ModuleItemList::new_green(self.db, module_items);
let rbrace = self.parse_token::<TerminalRBrace>();
ModuleBody::new_green(self.db, lbrace, items, rbrace).into()
}
_ => self.parse_token::<TerminalSemicolon>().into(),
};
ItemModule::new_green(self.db, attributes, visibility, module_kw, name, body)
}
fn expect_item_struct(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ItemStructGreen {
let struct_kw = self.take::<TerminalStruct>();
let name = self.parse_identifier();
let generic_params = self.parse_optional_generic_params();
let lbrace = self.parse_token::<TerminalLBrace>();
let members = self.parse_member_list();
let rbrace = self.parse_token::<TerminalRBrace>();
ItemStruct::new_green(
self.db,
attributes,
visibility,
struct_kw,
name,
generic_params,
lbrace,
members,
rbrace,
)
}
fn expect_item_enum(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ItemEnumGreen {
let enum_kw = self.take::<TerminalEnum>();
let name = self.parse_identifier();
let generic_params = self.parse_optional_generic_params();
let lbrace = self.parse_token::<TerminalLBrace>();
let variants = self.parse_variant_list();
let rbrace = self.parse_token::<TerminalRBrace>();
ItemEnum::new_green(
self.db,
attributes,
visibility,
enum_kw,
name,
generic_params,
lbrace,
variants,
rbrace,
)
}
fn expect_item_type_alias(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ItemTypeAliasGreen {
let type_kw = self.take::<TerminalType>();
let name = self.parse_identifier();
let generic_params = self.parse_optional_generic_params();
let eq = self.parse_token::<TerminalEq>();
let ty = self.parse_type_expr();
let semicolon = self.parse_token::<TerminalSemicolon>();
ItemTypeAlias::new_green(
self.db,
attributes,
visibility,
type_kw,
name,
generic_params,
eq,
ty,
semicolon,
)
}
fn expect_function_signature(&mut self) -> FunctionSignatureGreen {
let lparen = self.parse_token::<TerminalLParen>();
let params = self.parse_param_list();
let rparen = self.parse_token::<TerminalRParen>();
let return_type_clause = self.parse_option_return_type_clause();
let implicits_clause = self.parse_option_implicits_clause();
let optional_no_panic = if self.peek().kind == SyntaxKind::TerminalNoPanic {
self.take::<TerminalNoPanic>().into()
} else {
OptionTerminalNoPanicEmpty::new_green(self.db).into()
};
FunctionSignature::new_green(
self.db,
lparen,
params,
rparen,
return_type_clause,
implicits_clause,
optional_no_panic,
)
}
fn expect_item_const(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ItemConstantGreen {
let const_kw = self.take::<TerminalConst>();
let name = self.parse_identifier();
let type_clause = self.parse_type_clause(ErrorRecovery {
should_stop: is_of_kind!(eq, semicolon, module_item_kw),
});
let eq = self.parse_token::<TerminalEq>();
let expr = self.parse_expr();
let semicolon = self.parse_token::<TerminalSemicolon>();
ItemConstant::new_green(
self.db,
attributes,
visibility,
const_kw,
name,
type_clause,
eq,
expr,
semicolon,
)
}
fn expect_item_extern<T: From<ItemExternFunctionGreen> + From<ItemExternTypeGreen>>(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> T {
match self.expect_item_extern_inner(attributes, visibility) {
ExternItem::Function(x) => x.into(),
ExternItem::Type(x) => x.into(),
}
}
fn expect_item_extern_inner(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ExternItem {
let extern_kw = self.take::<TerminalExtern>();
match self.peek().kind {
SyntaxKind::TerminalFunction => {
let declaration = self.expect_function_declaration();
let semicolon = self.parse_token::<TerminalSemicolon>();
ExternItem::Function(ItemExternFunction::new_green(
self.db,
attributes,
visibility,
extern_kw,
declaration,
semicolon,
))
}
_ => {
let type_kw = self.parse_token::<TerminalType>();
let name = self.parse_identifier();
let generic_params = self.parse_optional_generic_params();
let semicolon = self.parse_token::<TerminalSemicolon>();
ExternItem::Type(ItemExternType::new_green(
self.db,
attributes,
visibility,
extern_kw,
type_kw,
name,
generic_params,
semicolon,
))
}
}
}
fn expect_item_use(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ItemUseGreen {
let use_kw = self.take::<TerminalUse>();
let use_path = self.parse_use_path();
let semicolon = self.parse_token::<TerminalSemicolon>();
ItemUse::new_green(self.db, attributes, visibility, use_kw, use_path, semicolon)
}
fn try_parse_use_path(&mut self) -> TryParseResult<UsePathGreen> {
if !matches!(self.peek().kind, SyntaxKind::TerminalLBrace | SyntaxKind::TerminalIdentifier)
{
return Err(TryParseFailure::SkipToken);
}
Ok(self.parse_use_path())
}
fn parse_use_path(&mut self) -> UsePathGreen {
if self.peek().kind == SyntaxKind::TerminalLBrace {
let lbrace = self.parse_token::<TerminalLBrace>();
let items = UsePathList::new_green(self.db,
self.parse_separated_list::<
UsePath, TerminalComma, UsePathListElementOrSeparatorGreen
>(
Self::try_parse_use_path,
is_of_kind!(rbrace, module_item_kw),
"path segment",
));
let rbrace = self.parse_token::<TerminalRBrace>();
UsePathMulti::new_green(self.db, lbrace, items, rbrace).into()
} else if let Ok(ident) = self.try_parse_identifier() {
let ident = PathSegmentSimple::new_green(self.db, ident).into();
match self.peek().kind {
SyntaxKind::TerminalColonColon => {
let colon_colon = self.parse_token::<TerminalColonColon>();
let use_path = self.parse_use_path();
UsePathSingle::new_green(self.db, ident, colon_colon, use_path).into()
}
SyntaxKind::TerminalAs => {
let as_kw = self.take::<TerminalAs>();
let alias = self.parse_identifier();
let alias_clause = AliasClause::new_green(self.db, as_kw, alias).into();
UsePathLeaf::new_green(self.db, ident, alias_clause).into()
}
_ => {
let alias_clause = OptionAliasClauseEmpty::new_green(self.db).into();
UsePathLeaf::new_green(self.db, ident, alias_clause).into()
}
}
} else {
let missing = self.create_and_report_missing::<TerminalIdentifier>(
ParserDiagnosticKind::MissingPathSegment,
);
let ident = PathSegmentSimple::new_green(self.db, missing).into();
UsePathLeaf::new_green(
self.db,
ident,
OptionAliasClauseEmpty::new_green(self.db).into(),
)
.into()
}
}
fn try_parse_identifier(&mut self) -> TryParseResult<TerminalIdentifierGreen> {
if self.peek().kind.is_keyword_terminal() {
Ok(self.skip_token_and_return_missing::<TerminalIdentifier>(
ParserDiagnosticKind::ReservedIdentifier { identifier: self.peek().text.clone() },
))
} else if self.peek().kind == SyntaxKind::TerminalUnderscore {
Ok(self.skip_token_and_return_missing::<TerminalIdentifier>(
ParserDiagnosticKind::UnderscoreNotAllowedAsIdentifier,
))
} else {
self.try_parse_token::<TerminalIdentifier>()
}
}
fn is_peek_identifier_like(&self) -> bool {
let kind = self.peek().kind;
kind.is_keyword_terminal()
|| matches!(kind, SyntaxKind::TerminalUnderscore | SyntaxKind::TerminalIdentifier)
}
fn parse_identifier(&mut self) -> TerminalIdentifierGreen {
match self.try_parse_identifier() {
Ok(identifier) => identifier,
Err(_) => self.create_and_report_missing_terminal::<TerminalIdentifier>(),
}
}
fn parse_visibility(&mut self) -> VisibilityGreen {
match self.try_parse_visibility_pub() {
Some(visibility) => visibility.into(),
None => VisibilityDefault::new_green(self.db).into(),
}
}
fn try_parse_visibility_pub(&mut self) -> Option<VisibilityPubGreen> {
require(self.peek().kind == SyntaxKind::TerminalPub)?;
let pub_kw = self.take::<TerminalPub>();
let argument_clause = if self.peek().kind != SyntaxKind::TerminalLParen {
OptionVisibilityPubArgumentClauseEmpty::new_green(self.db).into()
} else {
let lparen = self.parse_token::<TerminalLParen>();
let argument = self.parse_token::<TerminalIdentifier>();
let rparen = self.parse_token::<TerminalRParen>();
VisibilityPubArgumentClause::new_green(self.db, lparen, argument, rparen).into()
};
Some(VisibilityPub::new_green(self.db, pub_kw, argument_clause))
}
fn try_parse_attribute_list(
&mut self,
expected_elements_str: &str,
) -> TryParseResult<AttributeListGreen> {
if self.peek().kind == SyntaxKind::TerminalHash {
Ok(self.parse_attribute_list(expected_elements_str))
} else {
Err(TryParseFailure::SkipToken)
}
}
fn parse_attribute_list(&mut self, expected_elements_str: &str) -> AttributeListGreen {
AttributeList::new_green(
self.db,
self.parse_list(
Self::try_parse_attribute,
|x| x != SyntaxKind::TerminalHash,
&or_an_attribute!(expected_elements_str),
),
)
}
fn try_parse_attribute(&mut self) -> TryParseResult<AttributeGreen> {
match self.peek().kind {
SyntaxKind::TerminalHash => {
let hash = self.take::<TerminalHash>();
let lbrack = self.parse_token::<TerminalLBrack>();
let attr = self.parse_path();
let arguments = self.try_parse_parenthesized_argument_list();
let rbrack = self.parse_token::<TerminalRBrack>();
Ok(Attribute::new_green(self.db, hash, lbrack, attr, arguments, rbrack))
}
_ => Err(TryParseFailure::SkipToken),
}
}
fn expect_function_declaration(&mut self) -> FunctionDeclarationGreen {
let function_kw = self.take::<TerminalFunction>();
let name = self.parse_identifier();
let generic_params = self.parse_optional_generic_params();
let signature = self.expect_function_signature();
FunctionDeclaration::new_green(self.db, function_kw, name, generic_params, signature)
}
fn expect_item_function_with_body(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> FunctionWithBodyGreen {
let declaration = self.expect_function_declaration();
let function_body = self.parse_block();
FunctionWithBody::new_green(self.db, attributes, visibility, declaration, function_body)
}
fn expect_item_trait(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ItemTraitGreen {
let trait_kw = self.take::<TerminalTrait>();
let name = self.parse_identifier();
let generic_params = self.parse_optional_generic_params();
let body = if self.peek().kind == SyntaxKind::TerminalLBrace {
let lbrace = self.take::<TerminalLBrace>();
let items = TraitItemList::new_green(
self.db,
self.parse_attributed_list(
Self::try_parse_trait_item,
is_of_kind!(rbrace, module_item_kw),
TRAIT_ITEM_DESCRIPTION,
),
);
let rbrace = self.parse_token::<TerminalRBrace>();
TraitBody::new_green(self.db, lbrace, items, rbrace).into()
} else {
self.parse_token::<TerminalSemicolon>().into()
};
ItemTrait::new_green(self.db, attributes, visibility, trait_kw, name, generic_params, body)
}
pub fn try_parse_trait_item(&mut self) -> TryParseResult<TraitItemGreen> {
let maybe_attributes = self.try_parse_attribute_list(TRAIT_ITEM_DESCRIPTION);
let (has_attrs, attributes) = match maybe_attributes {
Ok(attributes) => (true, attributes),
Err(_) => (false, AttributeList::new_green(self.db, vec![])),
};
match self.peek().kind {
SyntaxKind::TerminalFunction => Ok(self.expect_trait_item_function(attributes).into()),
SyntaxKind::TerminalType => Ok(self.expect_trait_item_type(attributes).into()),
SyntaxKind::TerminalConst => Ok(self.expect_trait_item_const(attributes).into()),
SyntaxKind::TerminalImpl => Ok(self.expect_trait_item_impl(attributes).into()),
_ => {
if has_attrs {
Ok(self.skip_taken_node_and_return_missing::<TraitItem>(
attributes,
ParserDiagnosticKind::AttributesWithoutTraitItem,
))
} else {
Err(TryParseFailure::SkipToken)
}
}
}
}
fn expect_trait_item_function(
&mut self,
attributes: AttributeListGreen,
) -> TraitItemFunctionGreen {
let declaration = self.expect_function_declaration();
let body = if self.peek().kind == SyntaxKind::TerminalLBrace {
self.parse_block().into()
} else {
self.parse_token::<TerminalSemicolon>().into()
};
TraitItemFunction::new_green(self.db, attributes, declaration, body)
}
fn expect_trait_item_type(&mut self, attributes: AttributeListGreen) -> TraitItemTypeGreen {
let type_kw = self.take::<TerminalType>();
let name = self.parse_identifier();
let generic_params = self.parse_optional_generic_params();
let semicolon = self.parse_token::<TerminalSemicolon>();
TraitItemType::new_green(self.db, attributes, type_kw, name, generic_params, semicolon)
}
fn expect_trait_item_const(
&mut self,
attributes: AttributeListGreen,
) -> TraitItemConstantGreen {
let const_kw = self.take::<TerminalConst>();
let name = self.parse_identifier();
let type_clause = self.parse_type_clause(ErrorRecovery {
should_stop: is_of_kind!(eq, semicolon, module_item_kw),
});
let semicolon = self.parse_token::<TerminalSemicolon>();
TraitItemConstant::new_green(self.db, attributes, const_kw, name, type_clause, semicolon)
}
fn expect_trait_item_impl(&mut self, attributes: AttributeListGreen) -> TraitItemImplGreen {
let impl_kw = self.take::<TerminalImpl>();
let name = self.parse_identifier();
let colon = self.parse_token::<TerminalColon>();
let trait_path = self.parse_type_path();
let semicolon = self.parse_token::<TerminalSemicolon>();
TraitItemImpl::new_green(self.db, attributes, impl_kw, name, colon, trait_path, semicolon)
}
fn expect_module_item_impl(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ModuleItemGreen {
match self.expect_item_impl_inner(attributes, visibility, false) {
ImplItemOrAlias::Item(green) => green.into(),
ImplItemOrAlias::Alias(green) => green.into(),
}
}
fn expect_impl_item_impl(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
) -> ItemImplAliasGreen {
extract_matches!(
self.expect_item_impl_inner(attributes, visibility, true),
ImplItemOrAlias::Alias
)
}
fn expect_item_impl_inner(
&mut self,
attributes: AttributeListGreen,
visibility: VisibilityGreen,
only_allow_alias: bool,
) -> ImplItemOrAlias {
let impl_kw = self.take::<TerminalImpl>();
let name = self.parse_identifier();
let generic_params = self.parse_optional_generic_params();
if self.peek().kind == SyntaxKind::TerminalEq || only_allow_alias {
let eq = self.parse_token::<TerminalEq>();
let impl_path = self.parse_type_path();
let semicolon = self.parse_token::<TerminalSemicolon>();
return ImplItemOrAlias::Alias(ItemImplAlias::new_green(
self.db,
attributes,
visibility,
impl_kw,
name,
generic_params,
eq,
impl_path,
semicolon,
));
}
let of_kw = self.parse_token::<TerminalOf>();
let trait_path = self.parse_type_path();
let body = if self.peek().kind == SyntaxKind::TerminalLBrace {
let lbrace = self.take::<TerminalLBrace>();
let items = ImplItemList::new_green(
self.db,
self.parse_attributed_list(
Self::try_parse_impl_item,
is_of_kind!(rbrace),
IMPL_ITEM_DESCRIPTION,
),
);
let rbrace = self.parse_token::<TerminalRBrace>();
ImplBody::new_green(self.db, lbrace, items, rbrace).into()
} else {
self.parse_token::<TerminalSemicolon>().into()
};
ImplItemOrAlias::Item(ItemImpl::new_green(
self.db,
attributes,
visibility,
impl_kw,
name,
generic_params,
of_kw,
trait_path,
body,
))
}
pub fn try_parse_impl_item(&mut self) -> TryParseResult<ImplItemGreen> {
let maybe_attributes = self.try_parse_attribute_list(IMPL_ITEM_DESCRIPTION);
let (has_attrs, attributes) = match maybe_attributes {
Ok(attributes) => (true, attributes),
Err(_) => (false, AttributeList::new_green(self.db, vec![])),
};
let visibility = VisibilityDefault::new_green(self.db).into();
match self.peek().kind {
SyntaxKind::TerminalFunction => {
Ok(self.expect_item_function_with_body(attributes, visibility).into())
}
SyntaxKind::TerminalType => {
Ok(self.expect_item_type_alias(attributes, visibility).into())
}
SyntaxKind::TerminalConst => Ok(self.expect_item_const(attributes, visibility).into()),
SyntaxKind::TerminalImpl => {
Ok(self.expect_impl_item_impl(attributes, visibility).into())
}
SyntaxKind::TerminalModule => {
Ok(self.expect_item_module(attributes, visibility).into())
}
SyntaxKind::TerminalStruct => {
Ok(self.expect_item_struct(attributes, visibility).into())
}
SyntaxKind::TerminalEnum => Ok(self.expect_item_enum(attributes, visibility).into()),
SyntaxKind::TerminalExtern => Ok(self.expect_item_extern(attributes, visibility)),
SyntaxKind::TerminalUse => Ok(self.expect_item_use(attributes, visibility).into()),
SyntaxKind::TerminalTrait => Ok(self.expect_item_trait(attributes, visibility).into()),
_ => {
if has_attrs {
Ok(self.skip_taken_node_and_return_missing::<ImplItem>(
attributes,
ParserDiagnosticKind::AttributesWithoutImplItem,
))
} else {
Err(TryParseFailure::SkipToken)
}
}
}
}
fn expect_item_inline_macro(
&mut self,
attributes: AttributeListGreen,
name: TerminalIdentifierGreen,
) -> ItemInlineMacroGreen {
let bang = self.parse_token::<TerminalNot>();
self.parse_item_inline_macro_given_bang(attributes, name, bang)
}
fn parse_item_inline_macro_given_bang(
&mut self,
attributes: AttributeListGreen,
name: TerminalIdentifierGreen,
bang: TerminalNotGreen,
) -> ItemInlineMacroGreen {
let arguments = self.parse_wrapped_arg_list();
let semicolon = self.parse_token::<TerminalSemicolon>();
ItemInlineMacro::new_green(self.db, attributes, name, bang, arguments, semicolon)
}
fn try_parse_expr(&mut self) -> TryParseResult<ExprGreen> {
self.try_parse_expr_limited(MAX_PRECEDENCE, LbraceAllowed::Allow)
}
pub fn parse_expr(&mut self) -> ExprGreen {
match self.try_parse_expr() {
Ok(green) => green,
Err(_) => {
self.create_and_report_missing::<Expr>(ParserDiagnosticKind::MissingExpression)
}
}
}
fn parse_binary_operator(&mut self) -> BinaryOperatorGreen {
match self.peek().kind {
SyntaxKind::TerminalDot => self.take::<TerminalDot>().into(),
SyntaxKind::TerminalMul => self.take::<TerminalMul>().into(),
SyntaxKind::TerminalMulEq => self.take::<TerminalMulEq>().into(),
SyntaxKind::TerminalDiv => self.take::<TerminalDiv>().into(),
SyntaxKind::TerminalDivEq => self.take::<TerminalDivEq>().into(),
SyntaxKind::TerminalMod => self.take::<TerminalMod>().into(),
SyntaxKind::TerminalModEq => self.take::<TerminalModEq>().into(),
SyntaxKind::TerminalPlus => self.take::<TerminalPlus>().into(),
SyntaxKind::TerminalPlusEq => self.take::<TerminalPlusEq>().into(),
SyntaxKind::TerminalMinus => self.take::<TerminalMinus>().into(),
SyntaxKind::TerminalMinusEq => self.take::<TerminalMinusEq>().into(),
SyntaxKind::TerminalEq => self.take::<TerminalEq>().into(),
SyntaxKind::TerminalEqEq => self.take::<TerminalEqEq>().into(),
SyntaxKind::TerminalNeq => self.take::<TerminalNeq>().into(),
SyntaxKind::TerminalLT => self.take::<TerminalLT>().into(),
SyntaxKind::TerminalGT => self.take::<TerminalGT>().into(),
SyntaxKind::TerminalLE => self.take::<TerminalLE>().into(),
SyntaxKind::TerminalGE => self.take::<TerminalGE>().into(),
SyntaxKind::TerminalAnd => self.take::<TerminalAnd>().into(),
SyntaxKind::TerminalAndAnd => self.take::<TerminalAndAnd>().into(),
SyntaxKind::TerminalOrOr => self.take::<TerminalOrOr>().into(),
SyntaxKind::TerminalOr => self.take::<TerminalOr>().into(),
SyntaxKind::TerminalXor => self.take::<TerminalXor>().into(),
SyntaxKind::TerminalDotDot => self.take::<TerminalDotDot>().into(),
_ => unreachable!(),
}
}
fn expect_unary_operator(&mut self) -> UnaryOperatorGreen {
match self.peek().kind {
SyntaxKind::TerminalAt => self.take::<TerminalAt>().into(),
SyntaxKind::TerminalNot => self.take::<TerminalNot>().into(),
SyntaxKind::TerminalBitNot => self.take::<TerminalBitNot>().into(),
SyntaxKind::TerminalMinus => self.take::<TerminalMinus>().into(),
SyntaxKind::TerminalMul => self.take::<TerminalMul>().into(),
_ => unreachable!(),
}
}
fn try_parse_expr_limited(
&mut self,
parent_precedence: usize,
lbrace_allowed: LbraceAllowed,
) -> TryParseResult<ExprGreen> {
let mut expr = self.try_parse_atom_or_unary(lbrace_allowed)?;
while let Some(precedence) = get_post_operator_precedence(self.peek().kind) {
if precedence >= parent_precedence {
return Ok(expr);
}
expr = if self.peek().kind == SyntaxKind::TerminalQuestionMark {
ExprErrorPropagate::new_green(self.db, expr, self.take::<TerminalQuestionMark>())
.into()
} else if self.peek().kind == SyntaxKind::TerminalLBrack {
let lbrack = self.take::<TerminalLBrack>();
let index_expr = self.parse_expr();
let rbrack = self.parse_token::<TerminalRBrack>();
ExprIndexed::new_green(self.db, expr, lbrack, index_expr, rbrack).into()
} else {
let op = self.parse_binary_operator();
let rhs = self.parse_expr_limited(precedence, lbrace_allowed);
ExprBinary::new_green(self.db, expr, op, rhs).into()
};
}
Ok(expr)
}
fn try_parse_atom_or_unary(
&mut self,
lbrace_allowed: LbraceAllowed,
) -> TryParseResult<ExprGreen> {
let Some(precedence) = get_unary_operator_precedence(self.peek().kind) else {
return self.try_parse_atom(lbrace_allowed);
};
let op = self.expect_unary_operator();
let expr = self.parse_expr_limited(precedence, lbrace_allowed);
Ok(ExprUnary::new_green(self.db, op, expr).into())
}
fn parse_expr_limited(
&mut self,
parent_precedence: usize,
lbrace_allowed: LbraceAllowed,
) -> ExprGreen {
match self.try_parse_expr_limited(parent_precedence, lbrace_allowed) {
Ok(green) => green,
Err(_) => {
self.create_and_report_missing::<Expr>(ParserDiagnosticKind::MissingExpression)
}
}
}
fn try_parse_atom(&mut self, lbrace_allowed: LbraceAllowed) -> TryParseResult<ExprGreen> {
match self.peek().kind {
SyntaxKind::TerminalIdentifier => {
let path = self.parse_path();
match self.peek().kind {
SyntaxKind::TerminalLParen => Ok(self.expect_function_call(path).into()),
SyntaxKind::TerminalLBrace if lbrace_allowed == LbraceAllowed::Allow => {
Ok(self.expect_constructor_call(path).into())
}
SyntaxKind::TerminalNot => Ok(self.expect_macro_call(path).into()),
_ => Ok(path.into()),
}
}
SyntaxKind::TerminalFalse => Ok(self.take::<TerminalFalse>().into()),
SyntaxKind::TerminalTrue => Ok(self.take::<TerminalTrue>().into()),
SyntaxKind::TerminalLiteralNumber => Ok(self.take_terminal_literal_number().into()),
SyntaxKind::TerminalShortString => Ok(self.take_terminal_short_string().into()),
SyntaxKind::TerminalString => Ok(self.take_terminal_string().into()),
SyntaxKind::TerminalLParen => {
Ok(self.expect_parenthesized_expr())
}
SyntaxKind::TerminalLBrack => Ok(self.expect_fixed_size_array_expr().into()),
SyntaxKind::TerminalLBrace if lbrace_allowed == LbraceAllowed::Allow => {
Ok(self.parse_block().into())
}
SyntaxKind::TerminalMatch if lbrace_allowed == LbraceAllowed::Allow => {
Ok(self.expect_match_expr().into())
}
SyntaxKind::TerminalIf if lbrace_allowed == LbraceAllowed::Allow => {
Ok(self.expect_if_expr().into())
}
SyntaxKind::TerminalLoop if lbrace_allowed == LbraceAllowed::Allow => {
Ok(self.expect_loop_expr().into())
}
SyntaxKind::TerminalWhile if lbrace_allowed == LbraceAllowed::Allow => {
Ok(self.expect_while_expr().into())
}
SyntaxKind::TerminalFor if lbrace_allowed == LbraceAllowed::Allow => {
Ok(self.expect_for_expr().into())
}
SyntaxKind::TerminalOr if lbrace_allowed == LbraceAllowed::Allow => {
Ok(self.expect_closure_expr_nary().into())
}
SyntaxKind::TerminalOrOr if lbrace_allowed == LbraceAllowed::Allow => {
Ok(self.expect_closure_expr_nullary().into())
}
_ => {
Err(TryParseFailure::SkipToken)
}
}
}
fn try_parse_type_expr(&mut self) -> TryParseResult<ExprGreen> {
match self.peek().kind {
SyntaxKind::TerminalAt => {
let op = self.take::<TerminalAt>().into();
let expr = self.parse_type_expr();
Ok(ExprUnary::new_green(self.db, op, expr).into())
}
SyntaxKind::TerminalIdentifier => Ok(self.parse_type_path().into()),
SyntaxKind::TerminalLParen => Ok(self.expect_type_tuple_expr()),
SyntaxKind::TerminalLBrack => Ok(self.expect_type_fixed_size_array_expr()),
_ => {
Err(TryParseFailure::SkipToken)
}
}
}
fn parse_type_expr(&mut self) -> ExprGreen {
match self.try_parse_type_expr() {
Ok(expr) => expr,
Err(_) => {
self.create_and_report_missing::<Expr>(ParserDiagnosticKind::MissingTypeExpression)
}
}
}
fn expect_struct_ctor_argument_list_braced(&mut self) -> StructArgListBracedGreen {
let lbrace = self.take::<TerminalLBrace>();
let arg_list = StructArgList::new_green(
self.db,
self.parse_separated_list::<StructArg, TerminalComma, StructArgListElementOrSeparatorGreen>(
Self::try_parse_struct_ctor_argument,
is_of_kind!(rparen, block, rbrace, module_item_kw),
"struct constructor argument",
),
);
let rbrace = self.parse_token::<TerminalRBrace>();
StructArgListBraced::new_green(self.db, lbrace, arg_list, rbrace)
}
fn expect_function_call(&mut self, path: ExprPathGreen) -> ExprFunctionCallGreen {
let func_name = path;
let parenthesized_args = self.expect_parenthesized_argument_list();
ExprFunctionCall::new_green(self.db, func_name, parenthesized_args)
}
fn expect_macro_call(&mut self, path: ExprPathGreen) -> ExprInlineMacroGreen {
let bang = self.take::<TerminalNot>();
let macro_name = path;
let wrapped_expr_list = self.parse_wrapped_arg_list();
ExprInlineMacro::new_green(self.db, macro_name, bang, wrapped_expr_list)
}
fn parse_wrapped_arg_list(&mut self) -> WrappedArgListGreen {
let current_token = self.peek().kind;
match current_token {
SyntaxKind::TerminalLParen => self
.expect_wrapped_argument_list::<TerminalLParen, TerminalRParen, _, _>(
ArgListParenthesized::new_green,
)
.into(),
SyntaxKind::TerminalLBrack => self
.expect_wrapped_argument_list::<TerminalLBrack, TerminalRBrack, _, _>(
ArgListBracketed::new_green,
)
.into(),
SyntaxKind::TerminalLBrace => self
.expect_wrapped_argument_list::<TerminalLBrace, TerminalRBrace, _, _>(
ArgListBraced::new_green,
)
.into(),
_ => self.create_and_report_missing::<WrappedArgList>(
ParserDiagnosticKind::MissingWrappedArgList,
),
}
}
fn expect_wrapped_argument_list<
LTerminal: syntax::node::Terminal,
RTerminal: syntax::node::Terminal,
ListGreen,
NewGreen: Fn(&dyn SyntaxGroup, LTerminal::Green, ArgListGreen, RTerminal::Green) -> ListGreen,
>(
&mut self,
new_green: NewGreen,
) -> ListGreen {
let l_term = self.take::<LTerminal>();
let exprs: Vec<ArgListElementOrSeparatorGreen> = self
.parse_separated_list::<Arg, TerminalComma, ArgListElementOrSeparatorGreen>(
Self::try_parse_function_argument,
is_of_kind!(rparen, rbrace, rbrack, block, module_item_kw),
"argument",
);
let r_term: <RTerminal as TypedSyntaxNode>::Green = self.parse_token::<RTerminal>();
new_green(self.db, l_term, ArgList::new_green(self.db, exprs), r_term)
}
fn expect_parenthesized_argument_list(&mut self) -> ArgListParenthesizedGreen {
self.expect_wrapped_argument_list::<TerminalLParen, TerminalRParen, _, _>(
ArgListParenthesized::new_green,
)
}
fn try_parse_parenthesized_argument_list(&mut self) -> OptionArgListParenthesizedGreen {
if self.peek().kind == SyntaxKind::TerminalLParen {
self.expect_parenthesized_argument_list().into()
} else {
OptionArgListParenthesizedEmpty::new_green(self.db).into()
}
}
fn try_parse_function_argument(&mut self) -> TryParseResult<ArgGreen> {
let modifiers_list = self.parse_modifier_list();
let arg_clause = self.try_parse_argument_clause();
match arg_clause {
Ok(arg_clause) => {
let modifiers = ModifierList::new_green(self.db, modifiers_list);
Ok(Arg::new_green(self.db, modifiers, arg_clause))
}
Err(_) if !modifiers_list.is_empty() => {
let modifiers = ModifierList::new_green(self.db, modifiers_list);
let arg_clause = ArgClauseUnnamed::new_green(self.db, self.parse_expr()).into();
Ok(Arg::new_green(self.db, modifiers, arg_clause))
}
Err(err) => Err(err),
}
}
fn try_parse_argument_clause(&mut self) -> TryParseResult<ArgClauseGreen> {
if self.peek().kind == SyntaxKind::TerminalColon {
let colon = self.take::<TerminalColon>();
let name = self.parse_identifier();
return Ok(ArgClauseFieldInitShorthand::new_green(
self.db,
colon,
ExprFieldInitShorthand::new_green(self.db, name),
)
.into());
}
let value = self.try_parse_expr()?;
if self.peek().kind == SyntaxKind::TerminalColon {
if let Some(argname) = self.try_extract_identifier(value) {
let colon = self.take::<TerminalColon>();
let expr = self.parse_expr();
return Ok(ArgClauseNamed::new_green(self.db, argname, colon, expr).into());
}
}
Ok(ArgClauseUnnamed::new_green(self.db, value).into())
}
fn try_extract_identifier(&self, expr: ExprGreen) -> Option<TerminalIdentifierGreen> {
let GreenNode {
kind: SyntaxKind::ExprPath,
details: GreenNodeDetails::Node { children: children0, .. },
} = &*expr.0.lookup_intern(self.db)
else {
return None;
};
let [path_segment] = children0[..] else {
return None;
};
let GreenNode {
kind: SyntaxKind::PathSegmentSimple,
details: GreenNodeDetails::Node { children: children1, .. },
} = &*path_segment.lookup_intern(self.db)
else {
return None;
};
let [ident] = children1[..] else {
return None;
};
let GreenNode { kind: SyntaxKind::TerminalIdentifier, .. } =
ident.lookup_intern(self.db).as_ref()
else {
return None;
};
Some(TerminalIdentifierGreen(ident))
}
fn expect_constructor_call(&mut self, path: ExprPathGreen) -> ExprStructCtorCallGreen {
let ctor_name = path;
let args = self.expect_struct_ctor_argument_list_braced();
ExprStructCtorCall::new_green(self.db, ctor_name, args)
}
fn expect_parenthesized_expr(&mut self) -> ExprGreen {
let lparen = self.take::<TerminalLParen>();
let exprs: Vec<ExprListElementOrSeparatorGreen> = self
.parse_separated_list::<Expr, TerminalComma, ExprListElementOrSeparatorGreen>(
Self::try_parse_expr,
is_of_kind!(rparen, block, rbrace, module_item_kw),
"expression",
);
let rparen = self.parse_token::<TerminalRParen>();
if let [ExprListElementOrSeparatorGreen::Element(expr)] = &exprs[..] {
ExprParenthesized::new_green(self.db, lparen, *expr, rparen).into()
} else {
ExprListParenthesized::new_green(
self.db,
lparen,
ExprList::new_green(self.db, exprs),
rparen,
)
.into()
}
}
fn expect_type_tuple_expr(&mut self) -> ExprGreen {
let lparen = self.take::<TerminalLParen>();
let exprs: Vec<ExprListElementOrSeparatorGreen> = self
.parse_separated_list::<Expr, TerminalComma, ExprListElementOrSeparatorGreen>(
Self::try_parse_type_expr,
is_of_kind!(rparen, block, rbrace, module_item_kw),
"type expression",
);
let rparen = self.parse_token::<TerminalRParen>();
if let [ExprListElementOrSeparatorGreen::Element(_)] = &exprs[..] {
self.diagnostics.add(ParserDiagnostic {
file_id: self.file_id,
kind: ParserDiagnosticKind::MissingToken(SyntaxKind::TokenComma),
span: TextSpan { start: self.offset, end: self.offset },
});
}
ExprListParenthesized::new_green(
self.db,
lparen,
ExprList::new_green(self.db, exprs),
rparen,
)
.into()
}
fn expect_type_fixed_size_array_expr(&mut self) -> ExprGreen {
let lbrack = self.take::<TerminalLBrack>();
let exprs: Vec<ExprListElementOrSeparatorGreen> = self
.parse_separated_list::<Expr, TerminalComma, ExprListElementOrSeparatorGreen>(
Self::try_parse_type_expr,
is_of_kind!(rbrack, semicolon),
"type expression",
);
let semicolon = self.parse_token::<TerminalSemicolon>();
let size_expr = self.parse_expr();
let fixed_size_array_size =
FixedSizeArraySize::new_green(self.db, semicolon, size_expr).into();
let rbrack = self.parse_token::<TerminalRBrack>();
ExprFixedSizeArray::new_green(
self.db,
lbrack,
ExprList::new_green(self.db, exprs),
fixed_size_array_size,
rbrack,
)
.into()
}
fn expect_struct_argument_tail(&mut self) -> StructArgTailGreen {
let dotdot = self.take::<TerminalDotDot>(); let expr = self.parse_expr();
StructArgTail::new_green(self.db, dotdot, expr)
}
fn try_parse_struct_ctor_argument(&mut self) -> TryParseResult<StructArgGreen> {
match self.peek().kind {
SyntaxKind::TerminalDotDot => Ok(self.expect_struct_argument_tail().into()),
_ => self.try_parse_argument_single().map(|arg| arg.into()),
}
}
fn parse_option_struct_arg_expression(&mut self) -> OptionStructArgExprGreen {
if self.peek().kind == SyntaxKind::TerminalColon {
let colon = self.take::<TerminalColon>();
let value = self.parse_expr();
StructArgExpr::new_green(self.db, colon, value).into()
} else {
OptionStructArgExprEmpty::new_green(self.db).into()
}
}
fn parse_option_expression_clause(&mut self) -> OptionExprClauseGreen {
if self.peek().kind == SyntaxKind::TerminalSemicolon {
OptionExprClauseEmpty::new_green(self.db).into()
} else {
let value = self.parse_expr();
ExprClause::new_green(self.db, value).into()
}
}
fn try_parse_argument_single(&mut self) -> TryParseResult<StructArgSingleGreen> {
let identifier = self.try_parse_identifier()?;
let struct_arg_expr = self.parse_option_struct_arg_expression(); Ok(StructArgSingle::new_green(self.db, identifier, struct_arg_expr))
}
fn parse_block(&mut self) -> ExprBlockGreen {
let skipped_tokens = self.skip_until(is_of_kind!(rbrace, lbrace, module_item_kw, block));
if let Err(SkippedError(span)) = skipped_tokens {
self.diagnostics.add(ParserDiagnostic {
file_id: self.file_id,
kind: ParserDiagnosticKind::SkippedElement { element_name: "'{'".into() },
span,
});
}
let is_rbrace_or_top_level = is_of_kind!(rbrace, module_item_kw);
if is_rbrace_or_top_level(self.peek().kind) {
return ExprBlock::new_green(
self.db,
self.create_and_report_missing_terminal::<TerminalLBrace>(),
StatementList::new_green(self.db, vec![]),
TerminalRBrace::missing(self.db),
);
}
let lbrace = self.parse_token_ex::<TerminalLBrace>(skipped_tokens.is_ok());
let statements = StatementList::new_green(
self.db,
self.parse_list(
Self::try_parse_statement,
is_of_kind!(rbrace, module_item_kw),
"statement",
),
);
let rbrace = self.parse_token::<TerminalRBrace>();
ExprBlock::new_green(self.db, lbrace, statements, rbrace)
}
fn expect_match_expr(&mut self) -> ExprMatchGreen {
let match_kw = self.take::<TerminalMatch>();
let expr = self.parse_expr_limited(MAX_PRECEDENCE, LbraceAllowed::Forbid);
let lbrace = self.parse_token::<TerminalLBrace>();
let arms = MatchArms::new_green(
self.db,
self.parse_separated_list::<MatchArm, TerminalComma, MatchArmsElementOrSeparatorGreen>(
Self::try_parse_match_arm,
is_of_kind!(block, rbrace, module_item_kw),
"match arm",
),
);
let rbrace = self.parse_token::<TerminalRBrace>();
ExprMatch::new_green(self.db, match_kw, expr, lbrace, arms, rbrace)
}
fn expect_if_expr(&mut self) -> ExprIfGreen {
let if_kw = self.take::<TerminalIf>();
let condition = self.parse_condition_expr();
let if_block = self.parse_block();
let else_clause = if self.peek().kind == SyntaxKind::TerminalElse {
let else_kw = self.take::<TerminalElse>();
let else_block_or_if = if self.peek().kind == SyntaxKind::TerminalIf {
self.expect_if_expr().into()
} else {
self.parse_block().into()
};
ElseClause::new_green(self.db, else_kw, else_block_or_if).into()
} else {
OptionElseClauseEmpty::new_green(self.db).into()
};
ExprIf::new_green(self.db, if_kw, condition, if_block, else_clause)
}
fn parse_condition_expr(&mut self) -> ConditionGreen {
if self.peek().kind == SyntaxKind::TerminalLet {
let let_kw = self.take::<TerminalLet>();
let pattern_list = self
.parse_separated_list_inner::<Pattern, TerminalOr, PatternListOrElementOrSeparatorGreen>(
Self::try_parse_pattern,
is_of_kind!(eq),
"pattern",
Some(ParserDiagnosticKind::DisallowedTrailingSeparatorOr),
);
let pattern_list_green = if pattern_list.is_empty() {
self.create_and_report_missing::<PatternListOr>(
ParserDiagnosticKind::MissingPatteren,
)
} else {
PatternListOr::new_green(self.db, pattern_list)
};
let eq = self.parse_token::<TerminalEq>();
let expr: ExprGreen = self.parse_expr_limited(MAX_PRECEDENCE, LbraceAllowed::Forbid);
ConditionLet::new_green(self.db, let_kw, pattern_list_green, eq, expr).into()
} else {
let condition = self.parse_expr_limited(MAX_PRECEDENCE, LbraceAllowed::Forbid);
ConditionExpr::new_green(self.db, condition).into()
}
}
fn expect_loop_expr(&mut self) -> ExprLoopGreen {
let loop_kw = self.take::<TerminalLoop>();
let body = self.parse_block();
ExprLoop::new_green(self.db, loop_kw, body)
}
fn expect_while_expr(&mut self) -> ExprWhileGreen {
let while_kw = self.take::<TerminalWhile>();
let condition = self.parse_condition_expr();
let body = self.parse_block();
ExprWhile::new_green(self.db, while_kw, condition, body)
}
fn expect_for_expr(&mut self) -> ExprForGreen {
let for_kw = self.take::<TerminalFor>();
let pattern = self.parse_pattern();
let ident = self.take_raw();
let in_identifier: TerminalIdentifierGreen = match ident.text.as_str() {
"in" => self.add_trivia_to_terminal::<TerminalIdentifier>(ident),
_ => {
self.append_skipped_token_to_pending_trivia(
ident,
ParserDiagnosticKind::SkippedElement { element_name: "'in'".into() },
);
TerminalIdentifier::missing(self.db)
}
};
let expression = self.parse_expr_limited(MAX_PRECEDENCE, LbraceAllowed::Forbid);
let body = self.parse_block();
ExprFor::new_green(self.db, for_kw, pattern, in_identifier, expression, body)
}
fn expect_closure_expr_nary(&mut self) -> ExprClosureGreen {
let leftor = self.take::<TerminalOr>();
let params = self.parse_closure_param_list();
let rightor = self.parse_token::<TerminalOr>();
self.parse_closure_expr_body(
ClosureParamWrapperNAry::new_green(self.db, leftor, params, rightor).into(),
)
}
fn expect_closure_expr_nullary(&mut self) -> ExprClosureGreen {
let wrapper = self.take::<TerminalOrOr>().into();
self.parse_closure_expr_body(wrapper)
}
fn parse_closure_expr_body(&mut self, wrapper: ClosureParamWrapperGreen) -> ExprClosureGreen {
let mut block_required = self.peek().kind == SyntaxKind::TerminalArrow;
let return_type_clause = self.parse_option_return_type_clause();
let optional_no_panic = if self.peek().kind == SyntaxKind::TerminalNoPanic {
block_required = true;
self.take::<TerminalNoPanic>().into()
} else {
OptionTerminalNoPanicEmpty::new_green(self.db).into()
};
let expr = if block_required { self.parse_block().into() } else { self.parse_expr() };
ExprClosure::new_green(self.db, wrapper, return_type_clause, optional_no_panic, expr)
}
fn expect_fixed_size_array_expr(&mut self) -> ExprFixedSizeArrayGreen {
let lbrack = self.take::<TerminalLBrack>();
let exprs: Vec<ExprListElementOrSeparatorGreen> = self
.parse_separated_list::<Expr, TerminalComma, ExprListElementOrSeparatorGreen>(
Self::try_parse_expr,
is_of_kind!(rbrack, semicolon),
"expression",
);
let size_green = if self.peek().kind == SyntaxKind::TerminalSemicolon {
let semicolon = self.take::<TerminalSemicolon>();
let size = self.parse_expr();
FixedSizeArraySize::new_green(self.db, semicolon, size).into()
} else {
OptionFixedSizeArraySizeEmpty::new_green(self.db).into()
};
let rbrack = self.parse_token::<TerminalRBrack>();
ExprFixedSizeArray::new_green(
self.db,
lbrack,
ExprList::new_green(self.db, exprs),
size_green,
rbrack,
)
}
pub fn try_parse_match_arm(&mut self) -> TryParseResult<MatchArmGreen> {
let pattern_list = self
.parse_separated_list_inner::<Pattern, TerminalOr, PatternListOrElementOrSeparatorGreen>(
Self::try_parse_pattern,
is_of_kind!(match_arrow, rparen, block, rbrace, module_item_kw),
"pattern",
Some(ParserDiagnosticKind::DisallowedTrailingSeparatorOr),
);
if pattern_list.is_empty() {
return Err(TryParseFailure::SkipToken);
}
let pattern_list_green = PatternListOr::new_green(self.db, pattern_list);
let arrow = self.parse_token::<TerminalMatchArrow>();
let expr = self.parse_expr();
Ok(MatchArm::new_green(self.db, pattern_list_green, arrow, expr))
}
fn try_parse_pattern(&mut self) -> TryParseResult<PatternGreen> {
let modifier_list = self.parse_modifier_list();
if !modifier_list.is_empty() {
let modifiers = ModifierList::new_green(self.db, modifier_list);
let name = self.parse_identifier();
return Ok(PatternIdentifier::new_green(self.db, modifiers, name).into());
};
Ok(match self.peek().kind {
SyntaxKind::TerminalLiteralNumber => self.take_terminal_literal_number().into(),
SyntaxKind::TerminalShortString => self.take_terminal_short_string().into(),
SyntaxKind::TerminalTrue => self.take::<TerminalTrue>().into(),
SyntaxKind::TerminalFalse => self.take::<TerminalFalse>().into(),
SyntaxKind::TerminalUnderscore => self.take::<TerminalUnderscore>().into(),
SyntaxKind::TerminalIdentifier => {
let path = self.parse_path();
match self.peek().kind {
SyntaxKind::TerminalLBrace => {
let lbrace = self.take::<TerminalLBrace>();
let params = PatternStructParamList::new_green(
self.db,
self.parse_separated_list::<
PatternStructParam,
TerminalComma,
PatternStructParamListElementOrSeparatorGreen>
(
Self::try_parse_pattern_struct_param,
is_of_kind!(rparen, block, rbrace, module_item_kw),
"struct pattern parameter",
),
);
let rbrace = self.parse_token::<TerminalRBrace>();
PatternStruct::new_green(self.db, path, lbrace, params, rbrace).into()
}
SyntaxKind::TerminalLParen => {
let lparen = self.take::<TerminalLParen>();
let pattern = self.parse_pattern();
let rparen = self.parse_token::<TerminalRParen>();
let inner_pattern =
PatternEnumInnerPattern::new_green(self.db, lparen, pattern, rparen);
PatternEnum::new_green(self.db, path, inner_pattern.into()).into()
}
_ => {
let green_node = path.0.lookup_intern(self.db);
let children = match &green_node.details {
GreenNodeDetails::Node { children, width: _ } => children,
_ => return Err(TryParseFailure::SkipToken),
};
match children.len() {
1 => path.into(),
_ => PatternEnum::new_green(
self.db,
path,
OptionPatternEnumInnerPatternEmpty::new_green(self.db).into(),
)
.into(),
}
}
}
}
SyntaxKind::TerminalLParen => {
let lparen = self.take::<TerminalLParen>();
let patterns = PatternList::new_green(self.db, self.parse_separated_list::<
Pattern,
TerminalComma,
PatternListElementOrSeparatorGreen>
(
Self::try_parse_pattern,
is_of_kind!(rparen, block, rbrace, module_item_kw),
"pattern",
));
let rparen = self.parse_token::<TerminalRParen>();
PatternTuple::new_green(self.db, lparen, patterns, rparen).into()
}
SyntaxKind::TerminalLBrack => {
let lbrack = self.take::<TerminalLBrack>();
let patterns = PatternList::new_green(self.db, self.parse_separated_list::<
Pattern,
TerminalComma,
PatternListElementOrSeparatorGreen>
(
Self::try_parse_pattern,
is_of_kind!(rbrack, block, rbrace, module_item_kw),
"pattern",
));
let rbrack = self.parse_token::<TerminalRBrack>();
PatternFixedSizeArray::new_green(self.db, lbrack, patterns, rbrack).into()
}
_ => return Err(TryParseFailure::SkipToken),
})
}
fn parse_pattern(&mut self) -> PatternGreen {
match self.try_parse_pattern() {
Ok(pattern) => pattern,
Err(_) => self.create_and_report_missing_terminal::<TerminalUnderscore>().into(),
}
}
fn try_parse_pattern_struct_param(&mut self) -> TryParseResult<PatternStructParamGreen> {
Ok(match self.peek().kind {
SyntaxKind::TerminalDotDot => self.take::<TerminalDotDot>().into(),
_ => {
let modifier_list = self.parse_modifier_list();
let name = if modifier_list.is_empty() {
self.try_parse_identifier()?
} else {
self.parse_identifier()
};
let modifiers = ModifierList::new_green(self.db, modifier_list);
if self.peek().kind == SyntaxKind::TerminalColon {
let colon = self.take::<TerminalColon>();
let pattern = self.parse_pattern();
PatternStructParamWithExpr::new_green(self.db, modifiers, name, colon, pattern)
.into()
} else {
PatternIdentifier::new_green(self.db, modifiers, name).into()
}
}
})
}
pub fn try_parse_statement(&mut self) -> TryParseResult<StatementGreen> {
let maybe_attributes = self.try_parse_attribute_list("Statement");
let (has_attrs, attributes) = match maybe_attributes {
Ok(attributes) => (true, attributes),
Err(_) => (false, AttributeList::new_green(self.db, vec![])),
};
match self.peek().kind {
SyntaxKind::TerminalLet => {
let let_kw = self.take::<TerminalLet>();
let pattern = self.parse_pattern();
let type_clause = self.parse_option_type_clause();
let eq = self.parse_token::<TerminalEq>();
let rhs = self.parse_expr();
let semicolon = self.parse_token::<TerminalSemicolon>();
Ok(StatementLet::new_green(
self.db,
attributes,
let_kw,
pattern,
type_clause,
eq,
rhs,
semicolon,
)
.into())
}
SyntaxKind::TerminalContinue => {
let continue_kw = self.take::<TerminalContinue>();
let semicolon = self.parse_token::<TerminalSemicolon>();
Ok(StatementContinue::new_green(self.db, attributes, continue_kw, semicolon).into())
}
SyntaxKind::TerminalReturn => {
let return_kw = self.take::<TerminalReturn>();
let expr = self.parse_option_expression_clause();
let semicolon = self.parse_token::<TerminalSemicolon>();
Ok(StatementReturn::new_green(self.db, attributes, return_kw, expr, semicolon)
.into())
}
SyntaxKind::TerminalBreak => {
let break_kw = self.take::<TerminalBreak>();
let expr = self.parse_option_expression_clause();
let semicolon = self.parse_token::<TerminalSemicolon>();
Ok(StatementBreak::new_green(self.db, attributes, break_kw, expr, semicolon).into())
}
SyntaxKind::TerminalConst => Ok(StatementItem::new_green(
self.db,
self.expect_item_const(attributes, VisibilityDefault::new_green(self.db).into())
.into(),
)
.into()),
_ => match self.try_parse_expr() {
Ok(expr) => {
let optional_semicolon = if self.peek().kind == SyntaxKind::TerminalSemicolon {
self.take::<TerminalSemicolon>().into()
} else {
OptionTerminalSemicolonEmpty::new_green(self.db).into()
};
Ok(StatementExpr::new_green(self.db, attributes, expr, optional_semicolon)
.into())
}
Err(_) if has_attrs => Ok(self.skip_taken_node_and_return_missing::<Statement>(
attributes,
ParserDiagnosticKind::AttributesWithoutStatement,
)),
Err(err) => Err(err),
},
}
}
fn parse_option_type_clause(&mut self) -> OptionTypeClauseGreen {
match self.try_parse_type_clause() {
Some(green) => green.into(),
None => OptionTypeClauseEmpty::new_green(self.db).into(),
}
}
fn parse_type_clause(&mut self, error_recovery: ErrorRecovery) -> TypeClauseGreen {
match self.try_parse_type_clause() {
Some(green) => green,
None => {
let res = self.create_and_report_missing::<TypeClause>(
ParserDiagnosticKind::MissingTypeClause,
);
self.skip_until(error_recovery.should_stop).ok();
res
}
}
}
fn try_parse_type_clause(&mut self) -> Option<TypeClauseGreen> {
if self.peek().kind == SyntaxKind::TerminalColon {
let colon = self.take::<TerminalColon>();
let ty = self.parse_type_expr();
Some(TypeClause::new_green(self.db, colon, ty))
} else {
None
}
}
fn parse_option_return_type_clause(&mut self) -> OptionReturnTypeClauseGreen {
if self.peek().kind == SyntaxKind::TerminalArrow {
let arrow = self.take::<TerminalArrow>();
let return_type = self.parse_type_expr();
ReturnTypeClause::new_green(self.db, arrow, return_type).into()
} else {
OptionReturnTypeClauseEmpty::new_green(self.db).into()
}
}
fn parse_option_implicits_clause(&mut self) -> OptionImplicitsClauseGreen {
if self.peek().kind == SyntaxKind::TerminalImplicits {
let implicits_kw = self.take::<TerminalImplicits>();
let lparen = self.parse_token::<TerminalLParen>();
let implicits = ImplicitsList::new_green(
self.db,
self.parse_separated_list::<ExprPath, TerminalComma, ImplicitsListElementOrSeparatorGreen>(
Self::try_parse_path,
is_of_kind!(rparen, lbrace, rbrace),
"implicit type",
),
);
let rparen = self.parse_token::<TerminalRParen>();
ImplicitsClause::new_green(self.db, implicits_kw, lparen, implicits, rparen).into()
} else {
OptionImplicitsClauseEmpty::new_green(self.db).into()
}
}
fn parse_param_list(&mut self) -> ParamListGreen {
ParamList::new_green(
self.db,
self.parse_separated_list::<Param, TerminalComma, ParamListElementOrSeparatorGreen>(
Self::try_parse_param,
is_of_kind!(rparen, block, lbrace, rbrace, module_item_kw),
"parameter",
),
)
}
fn parse_closure_param_list(&mut self) -> ParamListGreen {
ParamList::new_green(
self.db,
self.parse_separated_list::<Param, TerminalComma, ParamListElementOrSeparatorGreen>(
Self::try_parse_closure_param,
is_of_kind!(or, block, lbrace, rbrace, module_item_kw),
"parameter",
),
)
}
fn try_parse_modifier(&mut self) -> Option<ModifierGreen> {
match self.peek().kind {
SyntaxKind::TerminalRef => Some(self.take::<TerminalRef>().into()),
SyntaxKind::TerminalMut => Some(self.take::<TerminalMut>().into()),
_ => None,
}
}
fn parse_modifier_list(&mut self) -> Vec<ModifierGreen> {
let mut modifier_list = vec![];
while let Some(modifier) = self.try_parse_modifier() {
modifier_list.push(modifier);
}
modifier_list
}
fn try_parse_param(&mut self) -> TryParseResult<ParamGreen> {
let modifier_list = self.parse_modifier_list();
let name = if modifier_list.is_empty() {
self.try_parse_identifier()?
} else {
self.parse_identifier()
};
let type_clause = self
.parse_type_clause(ErrorRecovery {
should_stop: is_of_kind!(comma, rparen, module_item_kw),
})
.into();
Ok(Param::new_green(
self.db,
ModifierList::new_green(self.db, modifier_list),
name,
type_clause,
))
}
fn try_parse_closure_param(&mut self) -> TryParseResult<ParamGreen> {
let modifier_list = self.parse_modifier_list();
let name = if modifier_list.is_empty() {
self.try_parse_identifier()?
} else {
self.parse_identifier()
};
let type_clause = self.parse_option_type_clause();
Ok(Param::new_green(
self.db,
ModifierList::new_green(self.db, modifier_list),
name,
type_clause,
))
}
fn parse_member_list(&mut self) -> MemberListGreen {
MemberList::new_green(
self.db,
self.parse_separated_list::<Member, TerminalComma, MemberListElementOrSeparatorGreen>(
Self::try_parse_member,
is_of_kind!(rparen, block, lbrace, rbrace, module_item_kw),
"member or variant",
),
)
}
fn try_parse_member(&mut self) -> TryParseResult<MemberGreen> {
let attributes = self.try_parse_attribute_list("Struct member");
let visibility = self.parse_visibility();
let (name, attributes) = match attributes {
Ok(attributes) => (self.parse_identifier(), attributes),
Err(_) => (self.try_parse_identifier()?, AttributeList::new_green(self.db, vec![])),
};
let type_clause = self.parse_type_clause(ErrorRecovery {
should_stop: is_of_kind!(comma, rbrace, module_item_kw),
});
Ok(Member::new_green(self.db, attributes, visibility, name, type_clause))
}
fn parse_variant_list(&mut self) -> VariantListGreen {
VariantList::new_green(
self.db,
self.parse_separated_list::<Variant, TerminalComma, VariantListElementOrSeparatorGreen>(
Self::try_parse_variant,
is_of_kind!(rparen, block, lbrace, rbrace, module_item_kw),
"variant",
),
)
}
fn try_parse_variant(&mut self) -> TryParseResult<VariantGreen> {
let attributes = self.try_parse_attribute_list("Enum variant");
let (name, attributes) = match attributes {
Ok(attributes) => (self.parse_identifier(), attributes),
Err(_) => (self.try_parse_identifier()?, AttributeList::new_green(self.db, vec![])),
};
let type_clause = self.parse_option_type_clause();
Ok(Variant::new_green(self.db, attributes, name, type_clause))
}
fn parse_path(&mut self) -> ExprPathGreen {
let mut children: Vec<ExprPathElementOrSeparatorGreen> = vec![];
loop {
let (segment, optional_separator) = self.parse_path_segment();
children.push(segment.into());
if let Some(separator) = optional_separator {
children.push(separator.into());
continue;
}
break;
}
ExprPath::new_green(self.db, children)
}
fn try_parse_path(&mut self) -> TryParseResult<ExprPathGreen> {
if self.is_peek_identifier_like() {
Ok(self.parse_path())
} else {
Err(TryParseFailure::SkipToken)
}
}
fn parse_type_path(&mut self) -> ExprPathGreen {
let mut children: Vec<ExprPathElementOrSeparatorGreen> = vec![];
loop {
let (segment, optional_separator) = self.parse_type_path_segment();
children.push(segment.into());
if let Some(separator) = optional_separator {
children.push(separator.into());
continue;
}
break;
}
ExprPath::new_green(self.db, children)
}
fn parse_path_segment(&mut self) -> (PathSegmentGreen, Option<TerminalColonColonGreen>) {
let identifier = match self.try_parse_identifier() {
Ok(identifier) => identifier,
Err(_) => {
return (
self.create_and_report_missing::<PathSegment>(
ParserDiagnosticKind::MissingPathSegment,
),
None,
);
}
};
match self.try_parse_token::<TerminalColonColon>() {
Ok(separator) if self.peek().kind == SyntaxKind::TerminalLT => (
PathSegmentWithGenericArgs::new_green(
self.db,
identifier,
separator.into(),
self.expect_generic_args(),
)
.into(),
self.try_parse_token::<TerminalColonColon>().ok(),
),
optional_separator => {
(PathSegmentSimple::new_green(self.db, identifier).into(), optional_separator.ok())
}
}
}
fn parse_type_path_segment(&mut self) -> (PathSegmentGreen, Option<TerminalColonColonGreen>) {
let identifier = match self.try_parse_identifier() {
Ok(identifier) => identifier,
Err(_) => {
return (
self.create_and_report_missing::<PathSegment>(
ParserDiagnosticKind::MissingPathSegment,
),
None,
);
}
};
match self.try_parse_token::<TerminalColonColon>() {
Err(_) if self.peek().kind == SyntaxKind::TerminalLT => (
PathSegmentWithGenericArgs::new_green(
self.db,
identifier,
OptionTerminalColonColonEmpty::new_green(self.db).into(),
self.expect_generic_args(),
)
.into(),
None,
),
Ok(separator) if self.peek().kind == SyntaxKind::TerminalLT => (
PathSegmentWithGenericArgs::new_green(
self.db,
identifier,
separator.into(),
self.expect_generic_args(),
)
.into(),
self.try_parse_token::<TerminalColonColon>().ok(),
),
optional_separator => {
(PathSegmentSimple::new_green(self.db, identifier).into(), optional_separator.ok())
}
}
}
fn take_terminal_literal_number(&mut self) -> TerminalLiteralNumberGreen {
let text = self.peek().text.clone();
let green = self.take::<TerminalLiteralNumber>();
let span = TextSpan { start: self.offset, end: self.offset.add_width(self.current_width) };
validate_literal_number(self.diagnostics, text, span, self.file_id);
green
}
fn take_terminal_short_string(&mut self) -> TerminalShortStringGreen {
let text = self.peek().text.clone();
let green = self.take::<TerminalShortString>();
let span = TextSpan { start: self.offset, end: self.offset.add_width(self.current_width) };
validate_short_string(self.diagnostics, text, span, self.file_id);
green
}
fn take_terminal_string(&mut self) -> TerminalStringGreen {
let text = self.peek().text.clone();
let green = self.take::<TerminalString>();
let span = TextSpan { start: self.offset, end: self.offset.add_width(self.current_width) };
validate_string(self.diagnostics, text, span, self.file_id);
green
}
fn try_parse_generic_arg(&mut self) -> TryParseResult<GenericArgGreen> {
if self.peek().kind == SyntaxKind::TerminalUnderscore {
let underscore = self.take::<TerminalUnderscore>().into();
return Ok(GenericArgUnnamed::new_green(self.db, underscore).into());
}
let expr = match self.peek().kind {
SyntaxKind::TerminalLiteralNumber => self.take_terminal_literal_number().into(),
SyntaxKind::TerminalMinus => {
let op = self.take::<TerminalMinus>().into();
let expr = self.parse_token::<TerminalLiteralNumber>().into();
ExprUnary::new_green(self.db, op, expr).into()
}
SyntaxKind::TerminalShortString => self.take_terminal_short_string().into(),
SyntaxKind::TerminalTrue => self.take::<TerminalTrue>().into(),
SyntaxKind::TerminalFalse => self.take::<TerminalFalse>().into(),
SyntaxKind::TerminalLBrace => self.parse_block().into(),
_ => self.try_parse_type_expr()?,
};
if self.peek().kind == SyntaxKind::TerminalColon {
if let Some(argname) = self.try_extract_identifier(expr) {
let colon = self.take::<TerminalColon>();
let expr = if self.peek().kind == SyntaxKind::TerminalUnderscore {
self.take::<TerminalUnderscore>().into()
} else {
let expr = self.parse_type_expr();
GenericArgValueExpr::new_green(self.db, expr).into()
};
return Ok(GenericArgNamed::new_green(self.db, argname, colon, expr).into());
}
}
Ok(GenericArgUnnamed::new_green(
self.db,
GenericArgValueExpr::new_green(self.db, expr).into(),
)
.into())
}
fn expect_generic_args(&mut self) -> GenericArgsGreen {
let langle = self.take::<TerminalLT>();
let generic_args = GenericArgList::new_green(
self.db,
self.parse_separated_list::<GenericArg, TerminalComma, GenericArgListElementOrSeparatorGreen>(
Self::try_parse_generic_arg,
is_of_kind!(rangle, rparen, block, lbrace, rbrace, module_item_kw),
"generic arg",
),
);
let rangle = self.parse_token::<TerminalGT>();
GenericArgs::new_green(self.db, langle, generic_args, rangle)
}
fn expect_generic_params(&mut self) -> WrappedGenericParamListGreen {
let langle = self.take::<TerminalLT>();
let generic_params = GenericParamList::new_green(
self.db,
self.parse_separated_list::<GenericParam, TerminalComma, GenericParamListElementOrSeparatorGreen>(
Self::try_parse_generic_param,
is_of_kind!(rangle, rparen, block, lbrace, rbrace, module_item_kw),
"generic param",
),
);
let rangle = self.parse_token::<TerminalGT>();
WrappedGenericParamList::new_green(self.db, langle, generic_params, rangle)
}
fn parse_optional_generic_params(&mut self) -> OptionWrappedGenericParamListGreen {
if self.peek().kind != SyntaxKind::TerminalLT {
return OptionWrappedGenericParamListEmpty::new_green(self.db).into();
}
self.expect_generic_params().into()
}
fn try_parse_generic_param(&mut self) -> TryParseResult<GenericParamGreen> {
match self.peek().kind {
SyntaxKind::TerminalConst => {
let const_kw = self.take::<TerminalConst>();
let name = self.parse_identifier();
let colon = self.parse_token::<TerminalColon>();
let ty = self.parse_type_expr();
Ok(GenericParamConst::new_green(self.db, const_kw, name, colon, ty).into())
}
SyntaxKind::TerminalImpl => {
let impl_kw = self.take::<TerminalImpl>();
let name = self.parse_identifier();
let colon = self.parse_token::<TerminalColon>();
let trait_path = self.parse_type_path();
Ok(GenericParamImplNamed::new_green(self.db, impl_kw, name, colon, trait_path)
.into())
}
SyntaxKind::TerminalPlus => {
let plus = self.take::<TerminalPlus>();
let trait_path = self.parse_type_path();
Ok(GenericParamImplAnonymous::new_green(self.db, plus, trait_path).into())
}
SyntaxKind::TerminalMinus => {
let minus = self.take::<TerminalMinus>();
let trait_path = self.parse_type_path();
Ok(GenericParamNegativeImpl::new_green(self.db, minus, trait_path).into())
}
_ => Ok(GenericParamType::new_green(self.db, self.try_parse_identifier()?).into()),
}
}
fn parse_list<ElementGreen>(
&mut self,
try_parse_list_element: fn(&mut Self) -> TryParseResult<ElementGreen>,
should_stop: fn(SyntaxKind) -> bool,
expected_element: &str,
) -> Vec<ElementGreen> {
let mut children: Vec<ElementGreen> = Vec::new();
loop {
let parse_result = try_parse_list_element(self);
match parse_result {
Ok(element_green) => {
children.push(element_green);
}
Err(err) => {
if should_stop(self.peek().kind) {
break;
}
if err == TryParseFailure::SkipToken {
self.skip_token(ParserDiagnosticKind::SkippedElement {
element_name: expected_element.into(),
});
}
}
}
}
children
}
fn parse_attributed_list<ElementGreen>(
&mut self,
try_parse_list_element: fn(&mut Self) -> TryParseResult<ElementGreen>,
should_stop: fn(SyntaxKind) -> bool,
expected_element: &str,
) -> Vec<ElementGreen> {
self.parse_list::<ElementGreen>(
try_parse_list_element,
should_stop,
&or_an_attribute!(expected_element),
)
}
fn parse_separated_list_inner<
Element: TypedSyntaxNode,
Separator: syntax::node::Terminal,
ElementOrSeparatorGreen,
>(
&mut self,
try_parse_list_element: fn(&mut Self) -> TryParseResult<Element::Green>,
should_stop: fn(SyntaxKind) -> bool,
expected_element: &'static str,
forbid_trailing_separator: Option<ParserDiagnosticKind>,
) -> Vec<ElementOrSeparatorGreen>
where
ElementOrSeparatorGreen: From<Separator::Green> + From<Element::Green>,
{
let mut children: Vec<ElementOrSeparatorGreen> = Vec::new();
loop {
match try_parse_list_element(self) {
Err(_) if should_stop(self.peek().kind) => {
if let (Some(diagnostic_kind), true) =
(forbid_trailing_separator, !children.is_empty())
{
self.diagnostics.add(ParserDiagnostic {
file_id: self.file_id,
span: TextSpan { start: self.offset, end: self.offset },
kind: diagnostic_kind,
});
}
break;
}
Err(_) => {
self.skip_token(ParserDiagnosticKind::SkippedElement {
element_name: expected_element.into(),
});
continue;
}
Ok(element) => {
children.push(element.into());
}
};
let separator = match self.try_parse_token::<Separator>() {
Err(_) if should_stop(self.peek().kind) => {
break;
}
Err(_) => self.create_and_report_missing::<Separator>(
ParserDiagnosticKind::MissingToken(Separator::KIND),
),
Ok(separator) => separator,
};
children.push(separator.into());
}
children
}
fn parse_separated_list<
Element: TypedSyntaxNode,
Separator: syntax::node::Terminal,
ElementOrSeparatorGreen,
>(
&mut self,
try_parse_list_element: fn(&mut Self) -> TryParseResult<Element::Green>,
should_stop: fn(SyntaxKind) -> bool,
expected_element: &'static str,
) -> Vec<ElementOrSeparatorGreen>
where
ElementOrSeparatorGreen: From<Separator::Green> + From<Element::Green>,
{
self.parse_separated_list_inner::<Element, Separator, ElementOrSeparatorGreen>(
try_parse_list_element,
should_stop,
expected_element,
None,
)
}
fn peek(&self) -> &LexerTerminal {
&self.next_terminal
}
fn take_raw(&mut self) -> LexerTerminal {
self.offset = self.offset.add_width(self.current_width);
self.current_width = self.next_terminal.width(self.db);
self.last_trivia_length = trivia_total_width(self.db, &self.next_terminal.trailing_trivia);
let next_terminal = self.lexer.next().unwrap();
std::mem::replace(&mut self.next_terminal, next_terminal)
}
fn skip_token(&mut self, diagnostic_kind: ParserDiagnosticKind) {
if self.peek().kind == SyntaxKind::TerminalEndOfFile {
self.diagnostics.add(ParserDiagnostic {
file_id: self.file_id,
kind: diagnostic_kind,
span: TextSpan { start: self.offset, end: self.offset },
});
return;
}
let terminal = self.take_raw();
self.append_skipped_token_to_pending_trivia(terminal, diagnostic_kind);
}
fn append_skipped_token_to_pending_trivia(
&mut self,
terminal: LexerTerminal,
diagnostic_kind: ParserDiagnosticKind,
) {
let orig_offset = self.offset;
let diag_start =
self.offset.add_width(trivia_total_width(self.db, &terminal.leading_trivia));
let diag_end = diag_start.add_width(TextWidth::from_str(&terminal.text));
self.pending_trivia.extend(terminal.leading_trivia.clone());
self.pending_trivia.push(TokenSkipped::new_green(self.db, terminal.text).into());
self.pending_trivia.extend(terminal.trailing_trivia.clone());
self.pending_skipped_token_diagnostics.push(PendingParserDiagnostic {
kind: diagnostic_kind,
span: TextSpan { start: diag_start, end: diag_end },
leading_trivia_start: orig_offset,
trailing_trivia_end: diag_end
.add_width(trivia_total_width(self.db, &terminal.trailing_trivia)),
});
}
fn skip_taken_node_from_current_offset(
&mut self,
node_to_skip: impl Into<SkippedNodeGreen>,
diagnostic_kind: ParserDiagnosticKind,
) {
self.skip_taken_node_with_offset(
node_to_skip,
diagnostic_kind,
self.offset.add_width(self.current_width),
)
}
fn skip_taken_node_with_offset(
&mut self,
node_to_skip: impl Into<SkippedNodeGreen>,
diagnostic_kind: ParserDiagnosticKind,
end_of_node_offset: TextOffset,
) {
let trivium_green = TriviumSkippedNode::new_green(self.db, node_to_skip.into()).into();
self.pending_trivia.push(trivium_green);
let start_of_node_offset = end_of_node_offset.sub_width(trivium_green.0.width(self.db));
let diag_pos = end_of_node_offset
.sub_width(trailing_trivia_width(self.db, trivium_green.0).unwrap_or_default());
self.pending_skipped_token_diagnostics.push(PendingParserDiagnostic {
kind: diagnostic_kind,
span: TextSpan { start: diag_pos, end: diag_pos },
leading_trivia_start: start_of_node_offset,
trailing_trivia_end: end_of_node_offset,
});
}
fn skip_token_and_return_missing<ExpectedTerminal: syntax::node::Terminal>(
&mut self,
diagnostic: ParserDiagnosticKind,
) -> ExpectedTerminal::Green {
self.skip_token(diagnostic);
ExpectedTerminal::missing(self.db)
}
fn skip_taken_node_and_return_missing<ExpectedNode: TypedSyntaxNode>(
&mut self,
node_to_skip: impl Into<SkippedNodeGreen>,
diagnostic_kind: ParserDiagnosticKind,
) -> ExpectedNode::Green {
self.skip_taken_node_from_current_offset(node_to_skip, diagnostic_kind);
ExpectedNode::missing(self.db)
}
fn skip_until(&mut self, should_stop: fn(SyntaxKind) -> bool) -> Result<(), SkippedError> {
let mut diag_start = None;
let mut diag_end = None;
while !should_stop(self.peek().kind) {
let terminal = self.take_raw();
diag_start.get_or_insert(self.offset);
diag_end = Some(self.offset.add_width(TextWidth::from_str(&terminal.text)));
self.pending_trivia.extend(terminal.leading_trivia);
self.pending_trivia.push(TokenSkipped::new_green(self.db, terminal.text).into());
self.pending_trivia.extend(terminal.trailing_trivia);
}
if let (Some(diag_start), Some(diag_end)) = (diag_start, diag_end) {
Err(SkippedError(TextSpan { start: diag_start, end: diag_end }))
} else {
Ok(())
}
}
fn add_trivia_to_terminal<Terminal: syntax::node::Terminal>(
&mut self,
lexer_terminal: LexerTerminal,
) -> Terminal::Green {
let LexerTerminal { text, kind: _, leading_trivia, trailing_trivia } = lexer_terminal;
let token = Terminal::TokenType::new_green(self.db, text);
let mut new_leading_trivia = mem::take(&mut self.pending_trivia);
self.consume_pending_skipped_diagnostics();
new_leading_trivia.extend(leading_trivia);
Terminal::new_green(
self.db,
Trivia::new_green(self.db, new_leading_trivia),
token,
Trivia::new_green(self.db, trailing_trivia),
)
}
fn consume_pending_skipped_diagnostics(&mut self) {
let mut pending_skipped = self.pending_skipped_token_diagnostics.drain(..);
let Some(first) = pending_skipped.next() else {
return;
};
let mut current_diag = first;
for diag in pending_skipped {
if diag.kind == current_diag.kind
&& current_diag.trailing_trivia_end == diag.leading_trivia_start
{
current_diag = PendingParserDiagnostic {
span: TextSpan { start: current_diag.span.start, end: diag.span.end },
kind: diag.kind,
leading_trivia_start: current_diag.leading_trivia_start,
trailing_trivia_end: diag.trailing_trivia_end,
};
} else {
self.diagnostics.add(ParserDiagnostic {
file_id: self.file_id,
span: current_diag.span,
kind: current_diag.kind,
});
current_diag = diag;
}
}
self.diagnostics.add(ParserDiagnostic {
file_id: self.file_id,
span: current_diag.span,
kind: current_diag.kind,
});
}
fn take<Terminal: syntax::node::Terminal>(&mut self) -> Terminal::Green {
let token = self.take_raw();
assert_eq!(token.kind, Terminal::KIND);
self.add_trivia_to_terminal::<Terminal>(token)
}
fn take_doc(&mut self) -> Option<ItemHeaderDocGreen> {
let mut has_header_doc = false;
let mut split_index = 0;
for trivium in self.next_terminal.leading_trivia.iter() {
match trivium.0.lookup_intern(self.db).kind {
SyntaxKind::TokenSingleLineComment | SyntaxKind::TokenSingleLineInnerComment => {
has_header_doc = true;
}
SyntaxKind::TokenSingleLineDocComment => {
break;
}
_ => {}
}
split_index += 1;
}
if !has_header_doc {
return None;
}
let leading_trivia = self.next_terminal.leading_trivia.clone();
let (header_doc, rest) = leading_trivia.split_at(split_index);
self.next_terminal.leading_trivia = rest.to_vec();
let empty_lexer_terminal = LexerTerminal {
text: "".into(),
kind: SyntaxKind::TerminalEmpty,
leading_trivia: header_doc.to_vec(),
trailing_trivia: vec![],
};
self.offset = self.offset.add_width(empty_lexer_terminal.width(self.db));
let empty_terminal = self.add_trivia_to_terminal::<TerminalEmpty>(empty_lexer_terminal);
Some(ItemHeaderDoc::new_green(self.db, empty_terminal))
}
fn try_parse_token<Terminal: syntax::node::Terminal>(
&mut self,
) -> TryParseResult<Terminal::Green> {
if Terminal::KIND == self.peek().kind {
Ok(self.take::<Terminal>())
} else {
Err(TryParseFailure::SkipToken)
}
}
fn parse_token<Terminal: syntax::node::Terminal>(&mut self) -> Terminal::Green {
self.parse_token_ex::<Terminal>(true)
}
fn parse_token_ex<Terminal: syntax::node::Terminal>(
&mut self,
report_diagnostic: bool,
) -> Terminal::Green {
match self.try_parse_token::<Terminal>() {
Ok(green) => green,
Err(_) => {
if report_diagnostic {
self.create_and_report_missing_terminal::<Terminal>()
} else {
Terminal::missing(self.db)
}
}
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum LbraceAllowed {
Forbid,
Allow,
}
struct SkippedError(TextSpan);
struct ErrorRecovery {
should_stop: fn(SyntaxKind) -> bool,
}
enum ExternItem {
Function(ItemExternFunctionGreen),
Type(ItemExternTypeGreen),
}
#[derive(Debug)]
enum ImplItemOrAlias {
Item(ItemImplGreen),
Alias(ItemImplAliasGreen),
}
pub struct PendingParserDiagnostic {
pub span: TextSpan,
pub kind: ParserDiagnosticKind,
pub leading_trivia_start: TextOffset,
pub trailing_trivia_end: TextOffset,
}
fn trivia_total_width(db: &dyn SyntaxGroup, trivia: &[TriviumGreen]) -> TextWidth {
trivia.iter().map(|trivium| trivium.0.width(db)).sum::<TextWidth>()
}
fn trailing_trivia_width(db: &dyn SyntaxGroup, green_id: GreenId) -> Option<TextWidth> {
let node = green_id.lookup_intern(db);
if node.kind == SyntaxKind::Trivia {
return Some(node.width());
}
match &node.details {
GreenNodeDetails::Token(_) => Some(TextWidth::default()),
GreenNodeDetails::Node { children, .. } => {
for child in children.iter().rev() {
if let Some(width) = trailing_trivia_width(db, *child) {
return Some(width);
}
}
None
}
}
}