Provide more complete AST accessors to support usage in rustc

This commit is contained in:
Luca Barbieri 2020-04-03 21:12:09 +02:00 committed by Aleksey Kladov
parent 8595693287
commit 60f4d7bd8c
18 changed files with 433 additions and 211 deletions

View file

@ -1,5 +1,5 @@
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode, NameOwner, TypeParamsOwner}, ast::{self, AstNode, AstToken, NameOwner, TypeParamsOwner},
TextUnit, TextUnit,
}; };
use stdx::{format_to, SepBy}; use stdx::{format_to, SepBy};
@ -42,7 +42,7 @@ pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> {
if let Some(type_params) = type_params { if let Some(type_params) = type_params {
let lifetime_params = type_params let lifetime_params = type_params
.lifetime_params() .lifetime_params()
.filter_map(|it| it.lifetime_token()) .filter_map(|it| it.lifetime())
.map(|it| it.text().clone()); .map(|it| it.text().clone());
let type_params = let type_params =
type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());

View file

@ -1,7 +1,8 @@
use hir::Adt; use hir::Adt;
use ra_syntax::{ use ra_syntax::{
ast::{ ast::{
self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, self, AstNode, AstToken, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner,
VisibilityOwner,
}, },
TextUnit, T, TextUnit, T,
}; };
@ -105,7 +106,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
if let Some(type_params) = type_params { if let Some(type_params) = type_params {
let lifetime_params = type_params let lifetime_params = type_params
.lifetime_params() .lifetime_params()
.filter_map(|it| it.lifetime_token()) .filter_map(|it| it.lifetime())
.map(|it| it.text().clone()); .map(|it| it.text().clone());
let type_params = let type_params =
type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone());

View file

@ -1,5 +1,5 @@
use ra_syntax::{ use ra_syntax::{
ast::{self, AstNode}, ast::{self, AstElement, AstNode},
SyntaxKind::{ SyntaxKind::{
BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR,
WHITESPACE, WHITESPACE,
@ -124,7 +124,7 @@ fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> {
} }
} }
if ast::Stmt::cast(node.clone()).is_some() { if ast::Stmt::cast_element(node.clone().into()).is_some() {
return Some((node, false)); return Some((node, false));
} }

View file

@ -3,7 +3,7 @@ use std::iter::successors;
use ra_syntax::{ use ra_syntax::{
algo::{neighbor, SyntaxRewriter}, algo::{neighbor, SyntaxRewriter},
ast::{self, edit::AstNodeEdit, make}, ast::{self, edit::AstNodeEdit, make},
AstNode, Direction, InsertPosition, SyntaxElement, T, AstNode, AstToken, Direction, InsertPosition, SyntaxElement, T,
}; };
use crate::{Assist, AssistCtx, AssistId}; use crate::{Assist, AssistCtx, AssistId};
@ -82,7 +82,7 @@ fn try_merge_trees(old: &ast::UseTree, new: &ast::UseTree) -> Option<ast::UseTre
.filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']), .filter(|it| it.kind() != T!['{'] && it.kind() != T!['}']),
); );
let use_tree_list = lhs.use_tree_list()?; let use_tree_list = lhs.use_tree_list()?;
let pos = InsertPosition::Before(use_tree_list.r_curly()?.into()); let pos = InsertPosition::Before(use_tree_list.r_curly()?.syntax().clone().into());
let use_tree_list = use_tree_list.insert_children(pos, to_insert); let use_tree_list = use_tree_list.insert_children(pos, to_insert);
Some(lhs.with_use_tree_list(use_tree_list)) Some(lhs.with_use_tree_list(use_tree_list))
} }

View file

@ -60,10 +60,10 @@ pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> {
} else { } else {
// Unwrap `{ continue; }` // Unwrap `{ continue; }`
let (stmt,) = block.statements().next_tuple()?; let (stmt,) = block.statements().next_tuple()?;
if has_anything_else(stmt.syntax()) {
return None;
}
if let ast::Stmt::ExprStmt(expr_stmt) = stmt { if let ast::Stmt::ExprStmt(expr_stmt) = stmt {
if has_anything_else(expr_stmt.syntax()) {
return None;
}
let expr = expr_stmt.expr()?; let expr = expr_stmt.expr()?;
match expr.syntax().kind() { match expr.syntax().kind() {
CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr), CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr),

View file

@ -482,14 +482,17 @@ impl ExprCollector<'_> {
self.collect_block_items(&block); self.collect_block_items(&block);
let statements = block let statements = block
.statements() .statements()
.map(|s| match s { .filter_map(|s| match s {
ast::Stmt::LetStmt(stmt) => { ast::Stmt::LetStmt(stmt) => {
let pat = self.collect_pat_opt(stmt.pat()); let pat = self.collect_pat_opt(stmt.pat());
let type_ref = stmt.ascribed_type().map(TypeRef::from_ast); let type_ref = stmt.ascribed_type().map(TypeRef::from_ast);
let initializer = stmt.initializer().map(|e| self.collect_expr(e)); let initializer = stmt.initializer().map(|e| self.collect_expr(e));
Statement::Let { pat, type_ref, initializer } Some(Statement::Let { pat, type_ref, initializer })
} }
ast::Stmt::ExprStmt(stmt) => Statement::Expr(self.collect_expr_opt(stmt.expr())), ast::Stmt::ExprStmt(stmt) => {
Some(Statement::Expr(self.collect_expr_opt(stmt.expr())))
}
ast::Stmt::ModuleItem(_) => None,
}) })
.collect(); .collect();
let tail = block.expr().map(|e| self.collect_expr(e)); let tail = block.expr().map(|e| self.collect_expr(e));
@ -541,6 +544,7 @@ impl ExprCollector<'_> {
let ast_id = self.expander.ast_id(&def); let ast_id = self.expander.ast_id(&def);
(TraitLoc { container, ast_id }.intern(self.db).into(), def.name()) (TraitLoc { container, ast_id }.intern(self.db).into(), def.name())
} }
ast::ModuleItem::ExternBlock(_) => continue, // FIXME: collect from extern blocks
ast::ModuleItem::ImplDef(_) ast::ModuleItem::ImplDef(_)
| ast::ModuleItem::UseItem(_) | ast::ModuleItem::UseItem(_)
| ast::ModuleItem::ExternCrateItem(_) | ast::ModuleItem::ExternCrateItem(_)

View file

@ -266,6 +266,10 @@ impl RawItemsCollector {
self.add_macro(current_module, it); self.add_macro(current_module, it);
return; return;
} }
ast::ModuleItem::ExternBlock(_) => {
// FIXME: add extern block
return;
}
}; };
if let Some(name) = name { if let Some(name) = name {
let name = name.as_name(); let name = name.as_name();

View file

@ -28,7 +28,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
loop { loop {
let segment = path.segment()?; let segment = path.segment()?;
if segment.has_colon_colon() { if segment.coloncolon().is_some() {
kind = PathKind::Abs; kind = PathKind::Abs;
} }

View file

@ -34,7 +34,7 @@ pub(crate) fn lower_use_tree(
let alias = tree.alias().map(|a| { let alias = tree.alias().map(|a| {
a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias) a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
}); });
let is_glob = tree.has_star(); let is_glob = tree.star().is_some();
if let Some(ast_path) = tree.path() { if let Some(ast_path) = tree.path() {
// Handle self in a path. // Handle self in a path.
// E.g. `use something::{self, <...>}` // E.g. `use something::{self, <...>}`

View file

@ -84,6 +84,10 @@ impl RawVisibility {
let path = ModPath { kind: PathKind::Super(1), segments: Vec::new() }; let path = ModPath { kind: PathKind::Super(1), segments: Vec::new() };
RawVisibility::Module(path) RawVisibility::Module(path)
} }
ast::VisibilityKind::PubSelf => {
let path = ModPath { kind: PathKind::Plain, segments: Vec::new() };
RawVisibility::Module(path)
}
ast::VisibilityKind::Pub => RawVisibility::Public, ast::VisibilityKind::Pub => RawVisibility::Public,
} }
} }

View file

@ -23,7 +23,7 @@ use insta::assert_snapshot;
use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase};
use ra_syntax::{ use ra_syntax::{
algo, algo,
ast::{self, AstNode}, ast::{self, AstNode, AstToken},
}; };
use stdx::format_to; use stdx::format_to;
@ -101,7 +101,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let node = src_ptr.value.to_node(&src_ptr.file_syntax(&db)); let node = src_ptr.value.to_node(&src_ptr.file_syntax(&db));
let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) {
(self_param.self_kw_token().text_range(), "self".to_string()) (self_param.self_kw().unwrap().syntax().text_range(), "self".to_string())
} else { } else {
(src_ptr.value.range(), node.text().to_string().replace("\n", " ")) (src_ptr.value.range(), node.text().to_string().replace("\n", " "))
}; };

View file

@ -105,6 +105,7 @@ pub enum SyntaxKind {
DEFAULT_KW, DEFAULT_KW,
EXISTENTIAL_KW, EXISTENTIAL_KW,
UNION_KW, UNION_KW,
RAW_KW,
INT_NUMBER, INT_NUMBER,
FLOAT_NUMBER, FLOAT_NUMBER,
CHAR, CHAR,
@ -258,7 +259,7 @@ impl SyntaxKind {
| IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW | IMPL_KW | IN_KW | LET_KW | LOOP_KW | MACRO_KW | MATCH_KW | MOD_KW | MOVE_KW
| MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW | MUT_KW | PUB_KW | REF_KW | RETURN_KW | SELF_KW | STATIC_KW | STRUCT_KW | SUPER_KW
| TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW | TRAIT_KW | TRUE_KW | TRY_KW | TYPE_KW | UNSAFE_KW | USE_KW | WHERE_KW | WHILE_KW
| AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW => true, | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW | RAW_KW => true,
_ => false, _ => false,
} }
} }
@ -651,4 +652,7 @@ macro_rules! T {
( union ) => { ( union ) => {
$crate::SyntaxKind::UNION_KW $crate::SyntaxKind::UNION_KW
}; };
( raw ) => {
$crate::SyntaxKind::RAW_KW
};
} }

View file

@ -271,7 +271,7 @@ where
let pred = predicates.next().unwrap(); let pred = predicates.next().unwrap();
let mut bounds = pred.type_bound_list().unwrap().bounds(); let mut bounds = pred.type_bound_list().unwrap().bounds();
assert_eq!("'a", pred.lifetime_token().unwrap().text()); assert_eq!("'a", pred.lifetime().unwrap().text());
assert_bound("'b", bounds.next()); assert_bound("'b", bounds.next());
assert_bound("'c", bounds.next()); assert_bound("'c", bounds.next());

View file

@ -99,7 +99,7 @@ impl ast::ItemList {
None => match self.l_curly() { None => match self.l_curly() {
Some(it) => ( Some(it) => (
" ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(), " ".to_string() + &leading_indent(self.syntax()).unwrap_or_default(),
InsertPosition::After(it), InsertPosition::After(it.syntax().clone().into()),
), ),
None => return self.clone(), None => return self.clone(),
}, },
@ -109,10 +109,6 @@ impl ast::ItemList {
[ws.ws().into(), item.syntax().clone().into()].into(); [ws.ws().into(), item.syntax().clone().into()].into();
self.insert_children(position, to_insert) self.insert_children(position, to_insert)
} }
fn l_curly(&self) -> Option<SyntaxElement> {
self.syntax().children_with_tokens().find(|it| it.kind() == T!['{'])
}
} }
impl ast::RecordFieldList { impl ast::RecordFieldList {
@ -147,7 +143,7 @@ impl ast::RecordFieldList {
macro_rules! after_l_curly { macro_rules! after_l_curly {
() => {{ () => {{
let anchor = match self.l_curly() { let anchor = match self.l_curly() {
Some(it) => it, Some(it) => it.syntax().clone().into(),
None => return self.clone(), None => return self.clone(),
}; };
InsertPosition::After(anchor) InsertPosition::After(anchor)
@ -189,24 +185,20 @@ impl ast::RecordFieldList {
self.insert_children(position, to_insert) self.insert_children(position, to_insert)
} }
fn l_curly(&self) -> Option<SyntaxElement> {
self.syntax().children_with_tokens().find(|it| it.kind() == T!['{'])
}
} }
impl ast::TypeParam { impl ast::TypeParam {
#[must_use] #[must_use]
pub fn remove_bounds(&self) -> ast::TypeParam { pub fn remove_bounds(&self) -> ast::TypeParam {
let colon = match self.colon_token() { let colon = match self.colon() {
Some(it) => it, Some(it) => it,
None => return self.clone(), None => return self.clone(),
}; };
let end = match self.type_bound_list() { let end = match self.type_bound_list() {
Some(it) => it.syntax().clone().into(), Some(it) => it.syntax().clone().into(),
None => colon.clone().into(), None => colon.syntax().clone().into(),
}; };
self.replace_children(colon.into()..=end, iter::empty()) self.replace_children(colon.syntax().clone().into()..=end, iter::empty())
} }
} }
@ -305,8 +297,12 @@ impl ast::UseTree {
Some(it) => it, Some(it) => it,
None => return self.clone(), None => return self.clone(),
}; };
let use_tree = let use_tree = make::use_tree(
make::use_tree(suffix.clone(), self.use_tree_list(), self.alias(), self.has_star()); suffix.clone(),
self.use_tree_list(),
self.alias(),
self.star().is_some(),
);
let nested = make::use_tree_list(iter::once(use_tree)); let nested = make::use_tree_list(iter::once(use_tree));
return make::use_tree(prefix.clone(), Some(nested), None, false); return make::use_tree(prefix.clone(), Some(nested), None, false);

View file

@ -52,6 +52,10 @@ impl ast::RefExpr {
pub fn is_mut(&self) -> bool { pub fn is_mut(&self) -> bool {
self.syntax().children_with_tokens().any(|n| n.kind() == T![mut]) self.syntax().children_with_tokens().any(|n| n.kind() == T![mut])
} }
pub fn raw_token(&self) -> Option<SyntaxToken> {
None // FIXME: implement &raw
}
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]

View file

@ -4,7 +4,10 @@
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::{
ast::{self, child_opt, children, AstNode, AttrInput, NameOwner, SyntaxNode}, ast::{
self, child_opt, child_token_opt, children, AstElement, AstNode, AstToken, AttrInput,
NameOwner, SyntaxNode,
},
SmolStr, SyntaxElement, SmolStr, SyntaxElement,
SyntaxKind::*, SyntaxKind::*,
SyntaxToken, T, SyntaxToken, T,
@ -130,13 +133,6 @@ impl ast::PathSegment {
}; };
Some(res) Some(res)
} }
pub fn has_colon_colon(&self) -> bool {
match self.syntax.first_child_or_token().map(|s| s.kind()) {
Some(T![::]) => true,
_ => false,
}
}
} }
impl ast::Path { impl ast::Path {
@ -154,12 +150,6 @@ impl ast::Module {
} }
} }
impl ast::UseTree {
pub fn has_star(&self) -> bool {
self.syntax().children_with_tokens().any(|it| it.kind() == T![*])
}
}
impl ast::UseTreeList { impl ast::UseTreeList {
pub fn parent_use_tree(&self) -> ast::UseTree { pub fn parent_use_tree(&self) -> ast::UseTree {
self.syntax() self.syntax()
@ -167,20 +157,6 @@ impl ast::UseTreeList {
.and_then(ast::UseTree::cast) .and_then(ast::UseTree::cast)
.expect("UseTreeLists are always nested in UseTrees") .expect("UseTreeLists are always nested in UseTrees")
} }
pub fn l_curly(&self) -> Option<SyntaxToken> {
self.token(T!['{'])
}
pub fn r_curly(&self) -> Option<SyntaxToken> {
self.token(T!['}'])
}
fn token(&self, kind: SyntaxKind) -> Option<SyntaxToken> {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == kind)
}
} }
impl ast::ImplDef { impl ast::ImplDef {
@ -387,24 +363,9 @@ pub enum SelfParamKind {
} }
impl ast::SelfParam { impl ast::SelfParam {
pub fn self_kw_token(&self) -> SyntaxToken {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == T![self])
.expect("invalid tree: self param must have self")
}
pub fn kind(&self) -> SelfParamKind { pub fn kind(&self) -> SelfParamKind {
let borrowed = self.syntax().children_with_tokens().any(|n| n.kind() == T![&]); if self.amp().is_some() {
if borrowed { if self.amp_mut_kw().is_some() {
// check for a `mut` coming after the & -- `mut &self` != `&mut self`
if self
.syntax()
.children_with_tokens()
.skip_while(|n| n.kind() != T![&])
.any(|n| n.kind() == T![mut])
{
SelfParamKind::MutRef SelfParamKind::MutRef
} else { } else {
SelfParamKind::Ref SelfParamKind::Ref
@ -413,32 +374,23 @@ impl ast::SelfParam {
SelfParamKind::Owned SelfParamKind::Owned
} }
} }
}
impl ast::LifetimeParam { /// the "mut" in "mut self", not the one in "&mut self"
pub fn lifetime_token(&self) -> Option<SyntaxToken> { pub fn mut_kw(&self) -> Option<ast::MutKw> {
self.syntax() self.syntax()
.children_with_tokens() .children_with_tokens()
.filter_map(|it| it.into_token()) .filter_map(|it| it.into_token())
.find(|it| it.kind() == LIFETIME) .take_while(|it| it.kind() != T![&])
.find_map(ast::MutKw::cast)
} }
}
impl ast::TypeParam { /// the "mut" in "&mut self", not the one in "mut self"
pub fn colon_token(&self) -> Option<SyntaxToken> { pub fn amp_mut_kw(&self) -> Option<ast::MutKw> {
self.syntax() self.syntax()
.children_with_tokens() .children_with_tokens()
.filter_map(|it| it.into_token()) .filter_map(|it| it.into_token())
.find(|it| it.kind() == T![:]) .skip_while(|it| it.kind() != T![&])
} .find_map(ast::MutKw::cast)
}
impl ast::WherePred {
pub fn lifetime_token(&self) -> Option<SyntaxToken> {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == LIFETIME)
} }
} }
@ -449,7 +401,7 @@ pub enum TypeBoundKind {
/// for<'a> ... /// for<'a> ...
ForType(ast::ForType), ForType(ast::ForType),
/// 'a /// 'a
Lifetime(ast::SyntaxToken), Lifetime(ast::Lifetime),
} }
impl ast::TypeBound { impl ast::TypeBound {
@ -465,21 +417,28 @@ impl ast::TypeBound {
} }
} }
fn lifetime(&self) -> Option<SyntaxToken> { pub fn has_question_mark(&self) -> bool {
self.syntax() self.question().is_some()
.children_with_tokens()
.filter_map(|it| it.into_token())
.find(|it| it.kind() == LIFETIME)
} }
pub fn question_mark_token(&self) -> Option<SyntaxToken> { pub fn const_question(&self) -> Option<ast::Question> {
self.syntax() self.syntax()
.children_with_tokens() .children_with_tokens()
.filter_map(|it| it.into_token()) .filter_map(|it| it.into_token())
.find(|it| it.kind() == T![?]) .take_while(|it| it.kind() != T![const])
.find_map(ast::Question::cast)
} }
pub fn has_question_mark(&self) -> bool {
self.question_mark_token().is_some() pub fn question(&self) -> Option<ast::Question> {
if self.const_kw().is_some() {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.into_token())
.skip_while(|it| it.kind() != T![const])
.find_map(ast::Question::cast)
} else {
child_token_opt(self)
}
} }
} }
@ -493,6 +452,7 @@ pub enum VisibilityKind {
In(ast::Path), In(ast::Path),
PubCrate, PubCrate,
PubSuper, PubSuper,
PubSelf,
Pub, Pub,
} }
@ -504,6 +464,8 @@ impl ast::Visibility {
VisibilityKind::PubCrate VisibilityKind::PubCrate
} else if self.is_pub_super() { } else if self.is_pub_super() {
VisibilityKind::PubSuper VisibilityKind::PubSuper
} else if self.is_pub_self() {
VisibilityKind::PubSuper
} else { } else {
VisibilityKind::Pub VisibilityKind::Pub
} }
@ -516,6 +478,10 @@ impl ast::Visibility {
fn is_pub_super(&self) -> bool { fn is_pub_super(&self) -> bool {
self.syntax().children_with_tokens().any(|it| it.kind() == T![super]) self.syntax().children_with_tokens().any(|it| it.kind() == T![super])
} }
fn is_pub_self(&self) -> bool {
self.syntax().children_with_tokens().any(|it| it.kind() == T![self])
}
} }
impl ast::MacroCall { impl ast::MacroCall {
@ -528,3 +494,41 @@ impl ast::MacroCall {
} }
} }
} }
impl ast::LifetimeParam {
pub fn lifetime_bounds(&self) -> impl Iterator<Item = ast::Lifetime> {
self.syntax()
.children_with_tokens()
.filter_map(|it| it.into_token())
.skip_while(|x| x.kind() != T![:])
.filter_map(ast::Lifetime::cast)
}
}
impl ast::RangePat {
pub fn start(&self) -> Option<ast::Pat> {
self.syntax()
.children_with_tokens()
.take_while(|it| !ast::RangeSeparator::can_cast_element(it.kind()))
.filter_map(|it| it.into_node())
.find_map(ast::Pat::cast)
}
pub fn end(&self) -> Option<ast::Pat> {
self.syntax()
.children_with_tokens()
.skip_while(|it| !ast::RangeSeparator::can_cast_element(it.kind()))
.filter_map(|it| it.into_node())
.find_map(ast::Pat::cast)
}
}
impl ast::TokenTree {
pub fn left_delimiter(&self) -> Option<ast::LeftDelimiter> {
self.syntax().first_child_or_token().and_then(ast::LeftDelimiter::cast_element)
}
pub fn right_delimiter(&self) -> Option<ast::RightDelimiter> {
self.syntax().last_child_or_token().and_then(ast::RightDelimiter::cast_element)
}
}

View file

@ -4,9 +4,9 @@
use itertools::Itertools; use itertools::Itertools;
use crate::{ use crate::ast::{
ast::{self, child_opt, children, AstChildren, AstNode, AstToken}, self, child_elements, child_opt, child_token_opt, child_tokens, children, AstChildElements,
syntax_node::SyntaxElementChildren, AstChildTokens, AstChildren, AstNode, AstToken,
}; };
pub trait TypeAscriptionOwner: AstNode { pub trait TypeAscriptionOwner: AstNode {
@ -31,6 +31,10 @@ pub trait LoopBodyOwner: AstNode {
fn loop_body(&self) -> Option<ast::BlockExpr> { fn loop_body(&self) -> Option<ast::BlockExpr> {
child_opt(self) child_opt(self)
} }
fn label(&self) -> Option<ast::Label> {
child_opt(self)
}
} }
pub trait ArgListOwner: AstNode { pub trait ArgListOwner: AstNode {
@ -65,6 +69,10 @@ pub trait TypeBoundsOwner: AstNode {
fn type_bound_list(&self) -> Option<ast::TypeBoundList> { fn type_bound_list(&self) -> Option<ast::TypeBoundList> {
child_opt(self) child_opt(self)
} }
fn colon(&self) -> Option<ast::Colon> {
child_token_opt(self)
}
} }
pub trait AttrsOwner: AstNode { pub trait AttrsOwner: AstNode {
@ -74,11 +82,14 @@ pub trait AttrsOwner: AstNode {
fn has_atom_attr(&self, atom: &str) -> bool { fn has_atom_attr(&self, atom: &str) -> bool {
self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom) self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom)
} }
fn attr_or_comments(&self) -> AstChildElements<ast::AttrOrComment> {
child_elements(self)
}
} }
pub trait DocCommentsOwner: AstNode { pub trait DocCommentsOwner: AstNode {
fn doc_comments(&self) -> CommentIter { fn doc_comments(&self) -> AstChildTokens<ast::Comment> {
CommentIter { iter: self.syntax().children_with_tokens() } child_tokens(self)
} }
/// Returns the textual content of a doc comment block as a single string. /// Returns the textual content of a doc comment block as a single string.
@ -123,14 +134,3 @@ pub trait DocCommentsOwner: AstNode {
} }
} }
} }
pub struct CommentIter {
iter: SyntaxElementChildren,
}
impl Iterator for CommentIter {
type Item = ast::Comment;
fn next(&mut self) -> Option<ast::Comment> {
self.iter.by_ref().find_map(|el| el.into_token().and_then(ast::Comment::cast))
}
}

View file

@ -70,7 +70,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc {
"match", "mod", "move", "mut", "pub", "ref", "return", "self", "static", "struct", "super", "match", "mod", "move", "mut", "pub", "ref", "return", "self", "static", "struct", "super",
"trait", "true", "try", "type", "unsafe", "use", "where", "while", "trait", "true", "try", "type", "unsafe", "use", "where", "while",
], ],
contextual_keywords: &["auto", "default", "existential", "union"], contextual_keywords: &["auto", "default", "existential", "union", "raw"],
literals: &[ literals: &[
"INT_NUMBER", "INT_NUMBER",
"FLOAT_NUMBER", "FLOAT_NUMBER",
@ -297,235 +297,311 @@ macro_rules! ast_enums {
pub(crate) const AST_SRC: AstSrc = AstSrc { pub(crate) const AST_SRC: AstSrc = AstSrc {
nodes: &ast_nodes! { nodes: &ast_nodes! {
struct SourceFile: ModuleItemOwner, FnDefOwner { struct SourceFile: ModuleItemOwner, FnDefOwner, AttrsOwner {
modules: [Module], modules: [Module],
} }
struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner { struct FnDef: VisibilityOwner, NameOwner, TypeParamsOwner, DocCommentsOwner, AttrsOwner {
Abi,
ConstKw,
DefaultKw,
AsyncKw,
UnsafeKw,
FnKw,
ParamList, ParamList,
RetType, RetType,
body: BlockExpr, body: BlockExpr,
Semi
} }
struct RetType { TypeRef } struct RetType { ThinArrow, TypeRef }
struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { struct StructDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
StructKw,
FieldDefList,
Semi
} }
struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { struct UnionDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
UnionKw,
RecordFieldDefList, RecordFieldDefList,
} }
struct RecordFieldDefList { fields: [RecordFieldDef] } struct RecordFieldDefList { LCurly, fields: [RecordFieldDef], RCurly }
struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { } struct RecordFieldDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { }
struct TupleFieldDefList { fields: [TupleFieldDef] } struct TupleFieldDefList { LParen, fields: [TupleFieldDef], RParen }
struct TupleFieldDef: VisibilityOwner, AttrsOwner { struct TupleFieldDef: VisibilityOwner, AttrsOwner {
TypeRef, TypeRef,
} }
struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner { struct EnumDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner {
EnumKw,
variant_list: EnumVariantList, variant_list: EnumVariantList,
} }
struct EnumVariantList { struct EnumVariantList {
LCurly,
variants: [EnumVariant], variants: [EnumVariant],
RCurly
} }
struct EnumVariant: NameOwner, DocCommentsOwner, AttrsOwner { struct EnumVariant: VisibilityOwner, NameOwner, DocCommentsOwner, AttrsOwner {
FieldDefList,
Eq,
Expr Expr
} }
struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner { struct TraitDef: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner, TypeParamsOwner, TypeBoundsOwner {
UnsafeKw,
AutoKw,
TraitKw,
ItemList, ItemList,
} }
struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner { struct Module: VisibilityOwner, NameOwner, AttrsOwner, DocCommentsOwner {
ModKw,
ItemList, ItemList,
Semi
} }
struct ItemList: FnDefOwner, ModuleItemOwner { struct ItemList: FnDefOwner, ModuleItemOwner {
LCurly,
impl_items: [ImplItem], impl_items: [ImplItem],
RCurly
} }
struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { struct ConstDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
DefaultKw,
ConstKw,
Eq,
body: Expr, body: Expr,
Semi
} }
struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner { struct StaticDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeAscriptionOwner {
StaticKw,
MutKw,
Eq,
body: Expr, body: Expr,
Semi
} }
struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner { struct TypeAliasDef: VisibilityOwner, NameOwner, TypeParamsOwner, AttrsOwner, DocCommentsOwner, TypeBoundsOwner {
DefaultKw,
TypeKw,
Eq,
TypeRef, TypeRef,
Semi
} }
struct ImplDef: TypeParamsOwner, AttrsOwner { struct ImplDef: TypeParamsOwner, AttrsOwner {
DefaultKw,
ConstKw,
UnsafeKw,
ImplKw,
Excl,
ForKw,
ItemList, ItemList,
} }
struct ParenType { TypeRef } struct ParenType { LParen, TypeRef, RParen }
struct TupleType { fields: [TypeRef] } struct TupleType { LParen, fields: [TypeRef], RParen }
struct NeverType { } struct NeverType { Excl }
struct PathType { Path } struct PathType { Path }
struct PointerType { TypeRef } struct PointerType { Star, ConstKw, TypeRef }
struct ArrayType { TypeRef, Expr } struct ArrayType { LBrack, TypeRef, Semi, Expr, RBrack }
struct SliceType { TypeRef } struct SliceType { LBrack, TypeRef, RBrack }
struct ReferenceType { TypeRef } struct ReferenceType { Amp, Lifetime, MutKw, TypeRef }
struct PlaceholderType { } struct PlaceholderType { Underscore }
struct FnPointerType { ParamList, RetType } struct FnPointerType { Abi, UnsafeKw, FnKw, ParamList, RetType }
struct ForType { TypeRef } struct ForType { ForKw, TypeParamList, TypeRef }
struct ImplTraitType: TypeBoundsOwner {} struct ImplTraitType: TypeBoundsOwner { ImplKw }
struct DynTraitType: TypeBoundsOwner {} struct DynTraitType: TypeBoundsOwner { DynKw }
struct TupleExpr { exprs: [Expr] } struct TupleExpr: AttrsOwner { LParen, exprs: [Expr], RParen }
struct ArrayExpr { exprs: [Expr] } struct ArrayExpr: AttrsOwner { LBrack, exprs: [Expr], Semi, RBrack }
struct ParenExpr { Expr } struct ParenExpr: AttrsOwner { LParen, Expr, RParen }
struct PathExpr { Path } struct PathExpr { Path }
struct LambdaExpr { struct LambdaExpr: AttrsOwner {
StaticKw,
AsyncKw,
MoveKw,
ParamList, ParamList,
RetType, RetType,
body: Expr, body: Expr,
} }
struct IfExpr { Condition } struct IfExpr: AttrsOwner { IfKw, Condition }
struct LoopExpr: LoopBodyOwner { } struct LoopExpr: AttrsOwner, LoopBodyOwner { LoopKw }
struct TryBlockExpr { body: BlockExpr } struct TryBlockExpr: AttrsOwner { TryKw, body: BlockExpr }
struct ForExpr: LoopBodyOwner { struct ForExpr: AttrsOwner, LoopBodyOwner {
ForKw,
Pat, Pat,
InKw,
iterable: Expr, iterable: Expr,
} }
struct WhileExpr: LoopBodyOwner { Condition } struct WhileExpr: AttrsOwner, LoopBodyOwner { WhileKw, Condition }
struct ContinueExpr {} struct ContinueExpr: AttrsOwner { ContinueKw, Lifetime }
struct BreakExpr { Expr } struct BreakExpr: AttrsOwner { BreakKw, Lifetime, Expr }
struct Label {} struct Label { Lifetime }
struct BlockExpr { Block } struct BlockExpr: AttrsOwner { Label, UnsafeKw, Block }
struct ReturnExpr { Expr } struct ReturnExpr: AttrsOwner { Expr }
struct CallExpr: ArgListOwner { Expr } struct CallExpr: ArgListOwner { Expr }
struct MethodCallExpr: ArgListOwner { struct MethodCallExpr: AttrsOwner, ArgListOwner {
Expr, NameRef, TypeArgList, Expr, Dot, NameRef, TypeArgList,
} }
struct IndexExpr {} struct IndexExpr: AttrsOwner { LBrack, RBrack }
struct FieldExpr { Expr, NameRef } struct FieldExpr: AttrsOwner { Expr, Dot, NameRef }
struct AwaitExpr { Expr } struct AwaitExpr: AttrsOwner { Expr, Dot, AwaitKw }
struct TryExpr { Expr } struct TryExpr: AttrsOwner { TryKw, Expr }
struct CastExpr { Expr, TypeRef } struct CastExpr: AttrsOwner { Expr, AsKw, TypeRef }
struct RefExpr { Expr } struct RefExpr: AttrsOwner { Amp, RawKw, MutKw, Expr }
struct PrefixExpr { Expr } struct PrefixExpr: AttrsOwner { PrefixOp, Expr }
struct BoxExpr { Expr } struct BoxExpr: AttrsOwner { BoxKw, Expr }
struct RangeExpr {} struct RangeExpr: AttrsOwner { RangeOp }
struct BinExpr {} struct BinExpr: AttrsOwner { BinOp }
struct Literal {} struct Literal { LiteralToken }
struct MatchExpr { Expr, MatchArmList } struct MatchExpr: AttrsOwner { MatchKw, Expr, MatchArmList }
struct MatchArmList: AttrsOwner { arms: [MatchArm] } struct MatchArmList: AttrsOwner { LCurly, arms: [MatchArm], RCurly }
struct MatchArm: AttrsOwner { struct MatchArm: AttrsOwner {
pat: Pat, pat: Pat,
guard: MatchGuard, guard: MatchGuard,
FatArrow,
Expr, Expr,
} }
struct MatchGuard { Expr } struct MatchGuard { IfKw, Expr }
struct RecordLit { Path, RecordFieldList } struct RecordLit { Path, RecordFieldList}
struct RecordFieldList { struct RecordFieldList {
LCurly,
fields: [RecordField], fields: [RecordField],
Dotdot,
spread: Expr, spread: Expr,
RCurly
} }
struct RecordField { NameRef, Expr } struct RecordField: AttrsOwner { NameRef, Colon, Expr }
struct OrPat { pats: [Pat] } struct OrPat { pats: [Pat] }
struct ParenPat { Pat } struct ParenPat { LParen, Pat, RParen }
struct RefPat { Pat } struct RefPat { Amp, MutKw, Pat }
struct BoxPat { Pat } struct BoxPat { BoxKw, Pat }
struct BindPat: NameOwner { Pat } struct BindPat: AttrsOwner, NameOwner { RefKw, MutKw, Pat }
struct PlaceholderPat { } struct PlaceholderPat { Underscore }
struct DotDotPat { } struct DotDotPat { Dotdot }
struct PathPat { Path } struct PathPat { Path }
struct SlicePat { args: [Pat] } struct SlicePat { LBrack, args: [Pat], RBrack }
struct RangePat {} struct RangePat { RangeSeparator }
struct LiteralPat { Literal } struct LiteralPat { Literal }
struct MacroPat { MacroCall } struct MacroPat { MacroCall }
struct RecordPat { RecordFieldPatList, Path } struct RecordPat { RecordFieldPatList, Path }
struct RecordFieldPatList { struct RecordFieldPatList {
LCurly,
pats: [RecordInnerPat],
record_field_pats: [RecordFieldPat], record_field_pats: [RecordFieldPat],
bind_pats: [BindPat], bind_pats: [BindPat],
Dotdot,
RCurly
} }
struct RecordFieldPat: NameOwner { Pat } struct RecordFieldPat: AttrsOwner, NameOwner { Colon, Pat }
struct TupleStructPat { Path, args: [Pat] } struct TupleStructPat { Path, LParen, args: [Pat], RParen }
struct TuplePat { args: [Pat] } struct TuplePat { LParen, args: [Pat], RParen }
struct Visibility {} struct Visibility { PubKw, SuperKw, SelfKw, CrateKw }
struct Name {} struct Name { Ident }
struct NameRef {} struct NameRef { NameRefToken }
struct MacroCall: NameOwner, AttrsOwner,DocCommentsOwner { struct MacroCall: NameOwner, AttrsOwner,DocCommentsOwner {
TokenTree, Path Path, Excl, TokenTree, Semi
} }
struct Attr { Path, input: AttrInput } struct Attr { Pound, Excl, LBrack, Path, Eq, input: AttrInput, RBrack }
struct TokenTree {} struct TokenTree {}
struct TypeParamList { struct TypeParamList {
LAngle,
generic_params: [GenericParam],
type_params: [TypeParam], type_params: [TypeParam],
lifetime_params: [LifetimeParam], lifetime_params: [LifetimeParam],
const_params: [ConstParam],
RAngle
} }
struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner { struct TypeParam: NameOwner, AttrsOwner, TypeBoundsOwner {
Eq,
default_type: TypeRef, default_type: TypeRef,
} }
struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner { struct ConstParam: NameOwner, AttrsOwner, TypeAscriptionOwner {
Eq,
default_val: Expr, default_val: Expr,
} }
struct LifetimeParam: AttrsOwner { } struct LifetimeParam: AttrsOwner { Lifetime}
struct TypeBound { TypeRef} struct TypeBound { Lifetime, /* Question, */ ConstKw, /* Question, */ TypeRef}
struct TypeBoundList { bounds: [TypeBound] } struct TypeBoundList { bounds: [TypeBound] }
struct WherePred: TypeBoundsOwner { TypeRef } struct WherePred: TypeBoundsOwner { Lifetime, TypeRef }
struct WhereClause { predicates: [WherePred] } struct WhereClause { WhereKw, predicates: [WherePred] }
struct ExprStmt { Expr } struct Abi { String }
struct LetStmt: TypeAscriptionOwner { struct ExprStmt: AttrsOwner { Expr, Semi }
struct LetStmt: AttrsOwner, TypeAscriptionOwner {
LetKw,
Pat, Pat,
Eq,
initializer: Expr, initializer: Expr,
} }
struct Condition { Pat, Expr } struct Condition { LetKw, Pat, Eq, Expr }
struct Block: AttrsOwner, ModuleItemOwner { struct Block: AttrsOwner, ModuleItemOwner {
LCurly,
statements: [Stmt], statements: [Stmt],
statements_or_semi: [StmtOrSemi],
Expr, Expr,
RCurly,
} }
struct ParamList { struct ParamList {
LParen,
SelfParam, SelfParam,
params: [Param], params: [Param],
RParen
} }
struct SelfParam: TypeAscriptionOwner, AttrsOwner { } struct SelfParam: TypeAscriptionOwner, AttrsOwner { Amp, Lifetime, SelfKw }
struct Param: TypeAscriptionOwner, AttrsOwner { struct Param: TypeAscriptionOwner, AttrsOwner {
Pat, Pat,
Dotdotdot
} }
struct UseItem: AttrsOwner, VisibilityOwner { struct UseItem: AttrsOwner, VisibilityOwner {
UseKw,
UseTree, UseTree,
} }
struct UseTree { struct UseTree {
Path, UseTreeList, Alias Path, Star, UseTreeList, Alias
} }
struct Alias: NameOwner { } struct Alias: NameOwner { AsKw }
struct UseTreeList { use_trees: [UseTree] } struct UseTreeList { LCurly, use_trees: [UseTree], RCurly }
struct ExternCrateItem: AttrsOwner, VisibilityOwner { struct ExternCrateItem: AttrsOwner, VisibilityOwner {
NameRef, Alias, ExternKw, CrateKw, NameRef, Alias,
} }
struct ArgList { struct ArgList {
LParen,
args: [Expr], args: [Expr],
RParen
} }
struct Path { struct Path {
segment: PathSegment, segment: PathSegment,
qualifier: Path, qualifier: Path,
} }
struct PathSegment { struct PathSegment {
NameRef, TypeArgList, ParamList, RetType, PathType, Coloncolon, LAngle, NameRef, TypeArgList, ParamList, RetType, PathType, RAngle
} }
struct TypeArgList { struct TypeArgList {
Coloncolon,
LAngle,
generic_args: [GenericArg],
type_args: [TypeArg], type_args: [TypeArg],
lifetime_args: [LifetimeArg], lifetime_args: [LifetimeArg],
assoc_type_args: [AssocTypeArg], assoc_type_args: [AssocTypeArg],
const_arg: [ConstArg], const_args: [ConstArg],
RAngle
} }
struct TypeArg { TypeRef } struct TypeArg { TypeRef }
struct AssocTypeArg { NameRef, TypeRef } struct AssocTypeArg : TypeBoundsOwner { NameRef, Eq, TypeRef }
struct LifetimeArg {} struct LifetimeArg { Lifetime }
struct ConstArg { Literal, BlockExpr } struct ConstArg { Literal, Eq, BlockExpr }
struct MacroItems: ModuleItemOwner, FnDefOwner { } struct MacroItems: ModuleItemOwner, FnDefOwner { }
@ -533,12 +609,44 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
statements: [Stmt], statements: [Stmt],
Expr, Expr,
} }
struct ExternItemList: FnDefOwner, ModuleItemOwner {
LCurly,
extern_items: [ExternItem],
RCurly
}
struct ExternBlock {
Abi,
ExternItemList
}
struct MetaItem {
Path, Eq, AttrInput, nested_meta_items: [MetaItem]
}
struct MacroDef {
Name, TokenTree
}
}, },
enums: &ast_enums! { enums: &ast_enums! {
enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner { enum NominalDef: NameOwner, TypeParamsOwner, AttrsOwner {
StructDef, EnumDef, UnionDef, StructDef, EnumDef, UnionDef,
} }
enum GenericParam {
LifetimeParam,
TypeParam,
ConstParam
}
enum GenericArg {
LifetimeArg,
TypeArg,
ConstArg,
AssocTypeArg
}
enum TypeRef { enum TypeRef {
ParenType, ParenType,
TupleType, TupleType,
@ -555,7 +663,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
DynTraitType, DynTraitType,
} }
enum ModuleItem: AttrsOwner, VisibilityOwner { enum ModuleItem: NameOwner, AttrsOwner, VisibilityOwner {
StructDef, StructDef,
UnionDef, UnionDef,
EnumDef, EnumDef,
@ -569,13 +677,20 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
StaticDef, StaticDef,
Module, Module,
MacroCall, MacroCall,
ExternBlock
} }
enum ImplItem: AttrsOwner { /* impl blocks can also contain MacroCall */
FnDef, TypeAliasDef, ConstDef, enum ImplItem: NameOwner, AttrsOwner {
FnDef, TypeAliasDef, ConstDef
} }
enum Expr { /* extern blocks can also contain MacroCall */
enum ExternItem: NameOwner, AttrsOwner, VisibilityOwner {
FnDef, StaticDef
}
enum Expr: AttrsOwner {
TupleExpr, TupleExpr,
ArrayExpr, ArrayExpr,
ParenExpr, ParenExpr,
@ -627,7 +742,93 @@ pub(crate) const AST_SRC: AstSrc = AstSrc {
MacroPat, MacroPat,
} }
enum RecordInnerPat {
RecordFieldPat,
BindPat
}
enum AttrInput { Literal, TokenTree } enum AttrInput { Literal, TokenTree }
enum Stmt { ExprStmt, LetStmt } enum Stmt {
ModuleItem,
LetStmt,
ExprStmt,
// macro calls are parsed as expression statements */
}
enum StmtOrSemi {Stmt, Semi}
enum LeftDelimiter { LParen, LBrack, LCurly }
enum RightDelimiter { RParen, RBrack, RCurly }
enum RangeSeparator { Dotdot, Dotdotdot, Dotdoteq}
enum BinOp {
Pipepipe,
Ampamp,
Eqeq,
Neq,
Lteq,
Gteq,
LAngle,
RAngle,
Plus,
Star,
Minus,
Slash,
Percent,
Shl,
Shr,
Caret,
Pipe,
Amp,
Eq,
Pluseq,
Slasheq,
Stareq,
Percenteq,
Shreq,
Shleq,
Minuseq,
Pipeeq,
Ampeq,
Careteq,
}
enum PrefixOp {
Minus,
Excl,
Star
}
enum RangeOp {
Dotdot,
Dotdoteq
}
enum LiteralToken {
IntNumber,
FloatNumber,
String,
RawString,
TrueKw,
FalseKw,
ByteString,
RawByteString,
Char,
Byte
}
enum NameRefToken {
Ident,
IntNumber
}
enum FieldDefList {
RecordFieldDefList,
TupleFieldDefList,
}
enum AttrOrComment {
Attr,
Comment
}
}, },
}; };