mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 21:13:37 +00:00
Make tt generic over the span data
This commit is contained in:
parent
d805c74c51
commit
41a46a78f2
48 changed files with 806 additions and 569 deletions
|
@ -6,7 +6,7 @@ use rustc_hash::FxHashMap;
|
||||||
use test_utils::{
|
use test_utils::{
|
||||||
extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER,
|
extract_range_or_offset, Fixture, RangeOrOffset, CURSOR_MARKER, ESCAPED_CURSOR_MARKER,
|
||||||
};
|
};
|
||||||
use tt::Subtree;
|
use tt::token_id::Subtree;
|
||||||
use vfs::{file_set::FileSet, VfsPath};
|
use vfs::{file_set::FileSet, VfsPath};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -495,16 +495,15 @@ impl ProcMacroExpander for MirrorProcMacroExpander {
|
||||||
_: &Env,
|
_: &Env,
|
||||||
) -> Result<Subtree, ProcMacroExpansionError> {
|
) -> Result<Subtree, ProcMacroExpansionError> {
|
||||||
fn traverse(input: &Subtree) -> Subtree {
|
fn traverse(input: &Subtree) -> Subtree {
|
||||||
let mut res = Subtree::default();
|
let mut token_trees = vec![];
|
||||||
res.delimiter = input.delimiter;
|
|
||||||
for tt in input.token_trees.iter().rev() {
|
for tt in input.token_trees.iter().rev() {
|
||||||
let tt = match tt {
|
let tt = match tt {
|
||||||
tt::TokenTree::Leaf(leaf) => tt::TokenTree::Leaf(leaf.clone()),
|
tt::TokenTree::Leaf(leaf) => tt::TokenTree::Leaf(leaf.clone()),
|
||||||
tt::TokenTree::Subtree(sub) => tt::TokenTree::Subtree(traverse(sub)),
|
tt::TokenTree::Subtree(sub) => tt::TokenTree::Subtree(traverse(sub)),
|
||||||
};
|
};
|
||||||
res.token_trees.push(tt);
|
token_trees.push(tt);
|
||||||
}
|
}
|
||||||
res
|
Subtree { delimiter: input.delimiter, token_trees }
|
||||||
}
|
}
|
||||||
Ok(traverse(input))
|
Ok(traverse(input))
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use cfg::CfgOptions;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use stdx::hash::{NoHashHashMap, NoHashHashSet};
|
use stdx::hash::{NoHashHashMap, NoHashHashSet};
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
use tt::Subtree;
|
use tt::token_id::Subtree;
|
||||||
use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath};
|
use vfs::{file_set::FileSet, AnchoredPath, FileId, VfsPath};
|
||||||
|
|
||||||
/// Files are grouped into source roots. A source root is a directory on the
|
/// Files are grouped into source roots. A source root is a directory on the
|
||||||
|
|
|
@ -66,7 +66,7 @@ impl From<CfgAtom> for CfgExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CfgExpr {
|
impl CfgExpr {
|
||||||
pub fn parse(tt: &tt::Subtree) -> CfgExpr {
|
pub fn parse<S>(tt: &tt::Subtree<S>) -> CfgExpr {
|
||||||
next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
|
next_cfg_expr(&mut tt.token_trees.iter()).unwrap_or(CfgExpr::Invalid)
|
||||||
}
|
}
|
||||||
/// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates.
|
/// Fold the cfg by querying all basic `Atom` and `KeyValue` predicates.
|
||||||
|
@ -85,7 +85,7 @@ impl CfgExpr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_cfg_expr(it: &mut SliceIter<'_, tt::TokenTree>) -> Option<CfgExpr> {
|
fn next_cfg_expr<S>(it: &mut SliceIter<'_, tt::TokenTree<S>>) -> Option<CfgExpr> {
|
||||||
let name = match it.next() {
|
let name = match it.next() {
|
||||||
None => return None,
|
None => return None,
|
||||||
Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(),
|
Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) => ident.text.clone(),
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
|
||||||
use base_db::CrateId;
|
use base_db::CrateId;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_expand::{
|
use hir_expand::{
|
||||||
|
@ -12,7 +13,6 @@ use intern::Interned;
|
||||||
use la_arena::{Arena, ArenaMap};
|
use la_arena::{Arena, ArenaMap};
|
||||||
use rustc_abi::{Integer, IntegerType};
|
use rustc_abi::{Integer, IntegerType};
|
||||||
use syntax::ast::{self, HasName, HasVisibility};
|
use syntax::ast::{self, HasName, HasVisibility};
|
||||||
use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{CfgExpander, LowerCtx},
|
body::{CfgExpander, LowerCtx},
|
||||||
|
@ -82,7 +82,7 @@ fn repr_from_value(
|
||||||
|
|
||||||
fn parse_repr_tt(tt: &Subtree) -> Option<ReprOptions> {
|
fn parse_repr_tt(tt: &Subtree) -> Option<ReprOptions> {
|
||||||
match tt.delimiter {
|
match tt.delimiter {
|
||||||
Some(Delimiter { kind: DelimiterKind::Parenthesis, .. }) => {}
|
Delimiter { kind: DelimiterKind::Parenthesis, .. } => {}
|
||||||
_ => return None,
|
_ => return None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ use syntax::{
|
||||||
ast::{self, HasAttrs, IsString},
|
ast::{self, HasAttrs, IsString},
|
||||||
AstPtr, AstToken, SmolStr, TextRange, TextSize,
|
AstPtr, AstToken, SmolStr, TextRange, TextSize,
|
||||||
};
|
};
|
||||||
use tt::Subtree;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
|
@ -234,7 +233,7 @@ impl Attrs {
|
||||||
|
|
||||||
pub fn has_doc_hidden(&self) -> bool {
|
pub fn has_doc_hidden(&self) -> bool {
|
||||||
self.by_key("doc").tt_values().any(|tt| {
|
self.by_key("doc").tt_values().any(|tt| {
|
||||||
tt.delimiter_kind() == Some(DelimiterKind::Parenthesis) &&
|
tt.delimiter.kind == DelimiterKind::Parenthesis &&
|
||||||
matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "hidden")
|
matches!(&*tt.token_trees, [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] if ident.text == "hidden")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -628,7 +627,7 @@ pub struct AttrQuery<'attr> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'attr> AttrQuery<'attr> {
|
impl<'attr> AttrQuery<'attr> {
|
||||||
pub fn tt_values(self) -> impl Iterator<Item = &'attr Subtree> {
|
pub fn tt_values(self) -> impl Iterator<Item = &'attr crate::tt::Subtree> {
|
||||||
self.attrs().filter_map(|attr| attr.token_tree_value())
|
self.attrs().filter_map(|attr| attr.token_tree_value())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ impl FunctionData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_rustc_legacy_const_generics(tt: &tt::Subtree) -> Box<[u32]> {
|
fn parse_rustc_legacy_const_generics(tt: &crate::tt::Subtree) -> Box<[u32]> {
|
||||||
let mut indices = Vec::new();
|
let mut indices = Vec::new();
|
||||||
for args in tt.token_trees.chunks(2) {
|
for args in tt.token_trees.chunks(2) {
|
||||||
match &args[0] {
|
match &args[0] {
|
||||||
|
|
|
@ -79,6 +79,8 @@ use nameres::DefMap;
|
||||||
use stdx::impl_from;
|
use stdx::impl_from;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
|
|
||||||
|
use ::tt::token_id as tt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
adt::VariantData,
|
adt::VariantData,
|
||||||
builtin_type::BuiltinType,
|
builtin_type::BuiltinType,
|
||||||
|
@ -973,15 +975,19 @@ fn attr_macro_as_call_id(
|
||||||
def: MacroDefId,
|
def: MacroDefId,
|
||||||
is_derive: bool,
|
is_derive: bool,
|
||||||
) -> MacroCallId {
|
) -> MacroCallId {
|
||||||
let mut arg = match macro_attr.input.as_deref() {
|
let arg = match macro_attr.input.as_deref() {
|
||||||
Some(AttrInput::TokenTree(tt, map)) => (tt.clone(), map.clone()),
|
Some(AttrInput::TokenTree(tt, map)) => (
|
||||||
_ => Default::default(),
|
{
|
||||||
|
let mut tt = tt.clone();
|
||||||
|
tt.delimiter = tt::Delimiter::UNSPECIFIED;
|
||||||
|
tt
|
||||||
|
},
|
||||||
|
map.clone(),
|
||||||
|
),
|
||||||
|
_ => (tt::Subtree::empty(), Default::default()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// The parentheses are always disposed here.
|
def.as_lazy_macro(
|
||||||
arg.0.delimiter = None;
|
|
||||||
|
|
||||||
let res = def.as_lazy_macro(
|
|
||||||
db.upcast(),
|
db.upcast(),
|
||||||
krate,
|
krate,
|
||||||
MacroCallKind::Attr {
|
MacroCallKind::Attr {
|
||||||
|
@ -990,8 +996,7 @@ fn attr_macro_as_call_id(
|
||||||
invoc_attr_index: macro_attr.id,
|
invoc_attr_index: macro_attr.id,
|
||||||
is_derive,
|
is_derive,
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
res
|
|
||||||
}
|
}
|
||||||
intern::impl_internable!(
|
intern::impl_internable!(
|
||||||
crate::type_ref::TypeRef,
|
crate::type_ref::TypeRef,
|
||||||
|
|
|
@ -30,7 +30,7 @@ use syntax::{
|
||||||
SyntaxKind::{self, COMMENT, EOF, IDENT, LIFETIME_IDENT},
|
SyntaxKind::{self, COMMENT, EOF, IDENT, LIFETIME_IDENT},
|
||||||
SyntaxNode, TextRange, T,
|
SyntaxNode, TextRange, T,
|
||||||
};
|
};
|
||||||
use tt::{Subtree, TokenId};
|
use tt::token_id::{Subtree, TokenId};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::DefDatabase, macro_id_to_def_id, nameres::ModuleSource, resolver::HasResolver,
|
db::DefDatabase, macro_id_to_def_id, nameres::ModuleSource, resolver::HasResolver,
|
||||||
|
@ -253,9 +253,9 @@ fn extract_id_ranges(ranges: &mut Vec<(TextRange, TokenId)>, map: &TokenMap, tre
|
||||||
tree.token_trees.iter().for_each(|tree| match tree {
|
tree.token_trees.iter().for_each(|tree| match tree {
|
||||||
tt::TokenTree::Leaf(leaf) => {
|
tt::TokenTree::Leaf(leaf) => {
|
||||||
let id = match leaf {
|
let id = match leaf {
|
||||||
tt::Leaf::Literal(it) => it.id,
|
tt::Leaf::Literal(it) => it.span,
|
||||||
tt::Leaf::Punct(it) => it.id,
|
tt::Leaf::Punct(it) => it.span,
|
||||||
tt::Leaf::Ident(it) => it.id,
|
tt::Leaf::Ident(it) => it.span,
|
||||||
};
|
};
|
||||||
ranges.extend(map.ranges_by_token(id, SyntaxKind::ERROR).map(|range| (range, id)));
|
ranges.extend(map.ranges_by_token(id, SyntaxKind::ERROR).map(|range| (range, id)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
path::{ImportAlias, ModPath, PathKind},
|
path::{ImportAlias, ModPath, PathKind},
|
||||||
per_ns::PerNs,
|
per_ns::PerNs,
|
||||||
|
tt,
|
||||||
visibility::{RawVisibility, Visibility},
|
visibility::{RawVisibility, Visibility},
|
||||||
AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId,
|
AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId,
|
||||||
FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc,
|
FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc,
|
||||||
|
@ -83,7 +84,8 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: T
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, it)| {
|
.map(|(idx, it)| {
|
||||||
// FIXME: a hacky way to create a Name from string.
|
// FIXME: a hacky way to create a Name from string.
|
||||||
let name = tt::Ident { text: it.name.clone(), id: tt::TokenId::unspecified() };
|
let name =
|
||||||
|
tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() };
|
||||||
(
|
(
|
||||||
name.as_name(),
|
name.as_name(),
|
||||||
ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)),
|
ProcMacroExpander::new(def_map.krate, base_db::ProcMacroId(idx as u32)),
|
||||||
|
@ -451,7 +453,10 @@ impl DefCollector<'_> {
|
||||||
directive.module_id,
|
directive.module_id,
|
||||||
MacroCallKind::Attr {
|
MacroCallKind::Attr {
|
||||||
ast_id: ast_id.ast_id,
|
ast_id: ast_id.ast_id,
|
||||||
attr_args: Default::default(),
|
attr_args: std::sync::Arc::new((
|
||||||
|
tt::Subtree::empty(),
|
||||||
|
Default::default(),
|
||||||
|
)),
|
||||||
invoc_attr_index: attr.id,
|
invoc_attr_index: attr.id,
|
||||||
is_derive: false,
|
is_derive: false,
|
||||||
},
|
},
|
||||||
|
@ -1947,7 +1952,8 @@ impl ModCollector<'_, '_> {
|
||||||
let name = match attrs.by_key("rustc_builtin_macro").string_value() {
|
let name = match attrs.by_key("rustc_builtin_macro").string_value() {
|
||||||
Some(it) => {
|
Some(it) => {
|
||||||
// FIXME: a hacky way to create a Name from string.
|
// FIXME: a hacky way to create a Name from string.
|
||||||
name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name();
|
name =
|
||||||
|
tt::Ident { text: it.clone(), span: tt::TokenId::unspecified() }.as_name();
|
||||||
&name
|
&name
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! Nameres-specific procedural macro data and helpers.
|
//! Nameres-specific procedural macro data and helpers.
|
||||||
|
|
||||||
use hir_expand::name::{AsName, Name};
|
use hir_expand::name::{AsName, Name};
|
||||||
use tt::{Leaf, TokenTree};
|
|
||||||
|
|
||||||
use crate::attr::Attrs;
|
use crate::attr::Attrs;
|
||||||
|
use crate::tt::{Leaf, TokenTree};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct ProcMacroDef {
|
pub struct ProcMacroDef {
|
||||||
|
|
|
@ -8,13 +8,13 @@ use intern::Interned;
|
||||||
use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
|
use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use syntax::{ast, match_ast, AstNode, SmolStr, SyntaxNode};
|
use syntax::{ast, match_ast, AstNode, SmolStr, SyntaxNode};
|
||||||
use tt::Subtree;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::AstDatabase,
|
db::AstDatabase,
|
||||||
hygiene::Hygiene,
|
hygiene::Hygiene,
|
||||||
mod_path::{ModPath, PathKind},
|
mod_path::{ModPath, PathKind},
|
||||||
name::AsName,
|
name::AsName,
|
||||||
|
tt::{self, Subtree},
|
||||||
InFile,
|
InFile,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,7 +117,10 @@ impl RawAttrs {
|
||||||
let index = attr.id;
|
let index = attr.id;
|
||||||
let attrs =
|
let attrs =
|
||||||
parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(|(idx, attr)| {
|
parts.enumerate().take(1 << AttrId::CFG_ATTR_BITS).filter_map(|(idx, attr)| {
|
||||||
let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
|
let tree = Subtree {
|
||||||
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
|
token_trees: attr.to_vec(),
|
||||||
|
};
|
||||||
// FIXME hygiene
|
// FIXME hygiene
|
||||||
let hygiene = Hygiene::new_unhygienic();
|
let hygiene = Hygiene::new_unhygienic();
|
||||||
Attr::from_tt(db, &tree, &hygiene, index.with_cfg_attr(idx))
|
Attr::from_tt(db, &tree, &hygiene, index.with_cfg_attr(idx))
|
||||||
|
@ -266,7 +269,7 @@ impl Attr {
|
||||||
pub fn parse_path_comma_token_tree(&self) -> Option<impl Iterator<Item = ModPath> + '_> {
|
pub fn parse_path_comma_token_tree(&self) -> Option<impl Iterator<Item = ModPath> + '_> {
|
||||||
let args = self.token_tree_value()?;
|
let args = self.token_tree_value()?;
|
||||||
|
|
||||||
if args.delimiter_kind() != Some(DelimiterKind::Parenthesis) {
|
if args.delimiter.kind != DelimiterKind::Parenthesis {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
let paths = args
|
let paths = args
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Builtin attributes.
|
//! Builtin attributes.
|
||||||
|
|
||||||
use crate::{db::AstDatabase, name, ExpandResult, MacroCallId, MacroCallKind};
|
use crate::{db::AstDatabase, name, tt, ExpandResult, MacroCallId, MacroCallKind};
|
||||||
|
|
||||||
macro_rules! register_builtin {
|
macro_rules! register_builtin {
|
||||||
( $(($name:ident, $variant:ident) => $expand:ident),* ) => {
|
( $(($name:ident, $variant:ident) => $expand:ident),* ) => {
|
||||||
|
@ -97,7 +97,7 @@ fn derive_attr_expand(
|
||||||
let loc = db.lookup_intern_macro_call(id);
|
let loc = db.lookup_intern_macro_call(id);
|
||||||
let derives = match &loc.kind {
|
let derives = match &loc.kind {
|
||||||
MacroCallKind::Attr { attr_args, is_derive: true, .. } => &attr_args.0,
|
MacroCallKind::Attr { attr_args, is_derive: true, .. } => &attr_args.0,
|
||||||
_ => return ExpandResult::ok(Default::default()),
|
_ => return ExpandResult::ok(tt::Subtree::empty()),
|
||||||
};
|
};
|
||||||
pseudo_derive_attr_expansion(tt, derives)
|
pseudo_derive_attr_expansion(tt, derives)
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ pub fn pseudo_derive_attr_expansion(
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
|
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
|
||||||
char,
|
char,
|
||||||
spacing: tt::Spacing::Alone,
|
spacing: tt::Spacing::Alone,
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
use base_db::{CrateOrigin, LangCrateOrigin};
|
use base_db::{CrateOrigin, LangCrateOrigin};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
use crate::tt::{self, TokenId};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstNode, HasGenericParams, HasModuleItem, HasName},
|
ast::{self, AstNode, HasGenericParams, HasModuleItem, HasName},
|
||||||
match_ast,
|
match_ast,
|
||||||
};
|
};
|
||||||
use tt::TokenId;
|
|
||||||
|
|
||||||
use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId};
|
use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId};
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
|
||||||
})?;
|
})?;
|
||||||
let name_token_id =
|
let name_token_id =
|
||||||
token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified);
|
token_map.token_by_range(name.syntax().text_range()).unwrap_or_else(TokenId::unspecified);
|
||||||
let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
|
let name_token = tt::Ident { span: name_token_id, text: name.text().into() };
|
||||||
let param_types = params
|
let param_types = params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.flat_map(|param_list| param_list.type_or_const_params())
|
.flat_map(|param_list| param_list.type_or_const_params())
|
||||||
|
@ -101,7 +101,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
|
||||||
let ty = param
|
let ty = param
|
||||||
.ty()
|
.ty()
|
||||||
.map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
|
.map(|ty| mbe::syntax_node_to_token_tree(ty.syntax()).0)
|
||||||
.unwrap_or_default();
|
.unwrap_or_else(tt::Subtree::empty);
|
||||||
Some(ty)
|
Some(ty)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -114,7 +114,7 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
|
||||||
fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
|
fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResult<tt::Subtree> {
|
||||||
let info = match parse_adt(tt) {
|
let info = match parse_adt(tt) {
|
||||||
Ok(info) => info,
|
Ok(info) => info,
|
||||||
Err(e) => return ExpandResult::only_err(e),
|
Err(e) => return ExpandResult::with_err(tt::Subtree::empty(), e),
|
||||||
};
|
};
|
||||||
let (params, args): (Vec<_>, Vec<_>) = info
|
let (params, args): (Vec<_>, Vec<_>) = info
|
||||||
.param_types
|
.param_types
|
||||||
|
@ -122,7 +122,7 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, param_ty)| {
|
.map(|(idx, param_ty)| {
|
||||||
let ident = tt::Leaf::Ident(tt::Ident {
|
let ident = tt::Leaf::Ident(tt::Ident {
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
text: format!("T{idx}").into(),
|
text: format!("T{idx}").into(),
|
||||||
});
|
});
|
||||||
let ident_ = ident.clone();
|
let ident_ = ident.clone();
|
||||||
|
|
|
@ -9,7 +9,9 @@ use syntax::{
|
||||||
SmolStr,
|
SmolStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{db::AstDatabase, name, quote, ExpandError, ExpandResult, MacroCallId, MacroCallLoc};
|
use crate::{
|
||||||
|
db::AstDatabase, name, quote, tt, ExpandError, ExpandResult, MacroCallId, MacroCallLoc,
|
||||||
|
};
|
||||||
|
|
||||||
macro_rules! register_builtin {
|
macro_rules! register_builtin {
|
||||||
( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => {
|
( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => {
|
||||||
|
@ -61,7 +63,7 @@ macro_rules! register_builtin {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
pub struct ExpandedEager {
|
pub struct ExpandedEager {
|
||||||
pub(crate) subtree: tt::Subtree,
|
pub(crate) subtree: tt::Subtree,
|
||||||
/// The included file ID of the include macro.
|
/// The included file ID of the include macro.
|
||||||
|
@ -116,7 +118,7 @@ register_builtin! {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DOLLAR_CRATE: tt::Ident =
|
const DOLLAR_CRATE: tt::Ident =
|
||||||
tt::Ident { text: SmolStr::new_inline("$crate"), id: tt::TokenId::unspecified() };
|
tt::Ident { text: SmolStr::new_inline("$crate"), span: tt::TokenId::unspecified() };
|
||||||
|
|
||||||
fn module_path_expand(
|
fn module_path_expand(
|
||||||
_db: &dyn AstDatabase,
|
_db: &dyn AstDatabase,
|
||||||
|
@ -162,7 +164,7 @@ fn stringify_expand(
|
||||||
_id: MacroCallId,
|
_id: MacroCallId,
|
||||||
tt: &tt::Subtree,
|
tt: &tt::Subtree,
|
||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<tt::Subtree> {
|
||||||
let pretty = tt::pretty(&tt.token_trees);
|
let pretty = ::tt::pretty(&tt.token_trees);
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
#pretty
|
#pretty
|
||||||
|
@ -194,11 +196,11 @@ fn assert_expand(
|
||||||
let expanded = match &*args {
|
let expanded = match &*args {
|
||||||
[cond, panic_args @ ..] => {
|
[cond, panic_args @ ..] => {
|
||||||
let comma = tt::Subtree {
|
let comma = tt::Subtree {
|
||||||
delimiter: None,
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
|
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
|
||||||
char: ',',
|
char: ',',
|
||||||
spacing: tt::Spacing::Alone,
|
spacing: tt::Spacing::Alone,
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}))],
|
}))],
|
||||||
};
|
};
|
||||||
let cond = cond.clone();
|
let cond = cond.clone();
|
||||||
|
@ -247,7 +249,10 @@ fn format_args_expand(
|
||||||
let mut args = parse_exprs_with_sep(tt, ',');
|
let mut args = parse_exprs_with_sep(tt, ',');
|
||||||
|
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return ExpandResult::only_err(mbe::ExpandError::NoMatchingRule.into());
|
return ExpandResult::with_err(
|
||||||
|
tt::Subtree::empty(),
|
||||||
|
mbe::ExpandError::NoMatchingRule.into(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for arg in &mut args {
|
for arg in &mut args {
|
||||||
// Remove `key =`.
|
// Remove `key =`.
|
||||||
|
@ -282,7 +287,7 @@ fn asm_expand(
|
||||||
for tt in tt.token_trees.chunks(2) {
|
for tt in tt.token_trees.chunks(2) {
|
||||||
match tt {
|
match tt {
|
||||||
[tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
|
[tt::TokenTree::Leaf(tt::Leaf::Literal(lit))]
|
||||||
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', id: _, spacing: _ }))] =>
|
| [tt::TokenTree::Leaf(tt::Leaf::Literal(lit)), tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', span: _, spacing: _ }))] =>
|
||||||
{
|
{
|
||||||
let krate = DOLLAR_CRATE.clone();
|
let krate = DOLLAR_CRATE.clone();
|
||||||
literals.push(quote!(#krate::format_args!(#lit);));
|
literals.push(quote!(#krate::format_args!(#lit);));
|
||||||
|
@ -400,7 +405,7 @@ fn concat_expand(
|
||||||
// FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
|
// FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
|
||||||
// to ensure the right parsing order, so skip the parentheses here. Ideally we'd
|
// to ensure the right parsing order, so skip the parentheses here. Ideally we'd
|
||||||
// implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623
|
// implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623
|
||||||
if let tt::TokenTree::Subtree(tt::Subtree { delimiter: Some(delim), token_trees }) = t {
|
if let tt::TokenTree::Subtree(tt::Subtree { delimiter: delim, token_trees }) = t {
|
||||||
if let [tt] = &**token_trees {
|
if let [tt] = &**token_trees {
|
||||||
if delim.kind == tt::DelimiterKind::Parenthesis {
|
if delim.kind == tt::DelimiterKind::Parenthesis {
|
||||||
t = tt;
|
t = tt;
|
||||||
|
@ -459,9 +464,7 @@ fn concat_bytes_expand(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
|
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
|
||||||
tt::TokenTree::Subtree(tree)
|
tt::TokenTree::Subtree(tree) if tree.delimiter.kind == tt::DelimiterKind::Bracket => {
|
||||||
if tree.delimiter_kind() == Some(tt::DelimiterKind::Bracket) =>
|
|
||||||
{
|
|
||||||
if let Err(e) = concat_bytes_expand_subtree(tree, &mut bytes) {
|
if let Err(e) = concat_bytes_expand_subtree(tree, &mut bytes) {
|
||||||
err.get_or_insert(e);
|
err.get_or_insert(e);
|
||||||
break;
|
break;
|
||||||
|
@ -473,7 +476,7 @@ fn concat_bytes_expand(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let ident = tt::Ident { text: bytes.join(", ").into(), id: tt::TokenId::unspecified() };
|
let ident = tt::Ident { text: bytes.join(", ").into(), span: tt::TokenId::unspecified() };
|
||||||
ExpandResult { value: ExpandedEager::new(quote!([#ident])), err }
|
ExpandResult { value: ExpandedEager::new(quote!([#ident])), err }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +524,7 @@ fn concat_idents_expand(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let ident = tt::Ident { text: ident.into(), id: tt::TokenId::unspecified() };
|
let ident = tt::Ident { text: ident.into(), span: tt::TokenId::unspecified() };
|
||||||
ExpandResult { value: ExpandedEager::new(quote!(#ident)), err }
|
ExpandResult { value: ExpandedEager::new(quote!(#ident)), err }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -572,7 +575,10 @@ fn include_expand(
|
||||||
Ok((subtree, file_id)) => {
|
Ok((subtree, file_id)) => {
|
||||||
ExpandResult::ok(ExpandedEager { subtree, included_file: Some(file_id) })
|
ExpandResult::ok(ExpandedEager { subtree, included_file: Some(file_id) })
|
||||||
}
|
}
|
||||||
Err(e) => ExpandResult::only_err(e),
|
Err(e) => ExpandResult::with_err(
|
||||||
|
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
|
||||||
|
e,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -582,15 +588,18 @@ fn include_bytes_expand(
|
||||||
tt: &tt::Subtree,
|
tt: &tt::Subtree,
|
||||||
) -> ExpandResult<ExpandedEager> {
|
) -> ExpandResult<ExpandedEager> {
|
||||||
if let Err(e) = parse_string(tt) {
|
if let Err(e) = parse_string(tt) {
|
||||||
return ExpandResult::only_err(e);
|
return ExpandResult::with_err(
|
||||||
|
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
|
||||||
|
e,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: actually read the file here if the user asked for macro expansion
|
// FIXME: actually read the file here if the user asked for macro expansion
|
||||||
let res = tt::Subtree {
|
let res = tt::Subtree {
|
||||||
delimiter: None,
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
|
||||||
text: r#"b"""#.into(),
|
text: r#"b"""#.into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}))],
|
}))],
|
||||||
};
|
};
|
||||||
ExpandResult::ok(ExpandedEager::new(res))
|
ExpandResult::ok(ExpandedEager::new(res))
|
||||||
|
@ -603,7 +612,12 @@ fn include_str_expand(
|
||||||
) -> ExpandResult<ExpandedEager> {
|
) -> ExpandResult<ExpandedEager> {
|
||||||
let path = match parse_string(tt) {
|
let path = match parse_string(tt) {
|
||||||
Ok(it) => it,
|
Ok(it) => it,
|
||||||
Err(e) => return ExpandResult::only_err(e),
|
Err(e) => {
|
||||||
|
return ExpandResult::with_err(
|
||||||
|
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: we're not able to read excluded files (which is most of them because
|
// FIXME: we're not able to read excluded files (which is most of them because
|
||||||
|
@ -635,7 +649,12 @@ fn env_expand(
|
||||||
) -> ExpandResult<ExpandedEager> {
|
) -> ExpandResult<ExpandedEager> {
|
||||||
let key = match parse_string(tt) {
|
let key = match parse_string(tt) {
|
||||||
Ok(it) => it,
|
Ok(it) => it,
|
||||||
Err(e) => return ExpandResult::only_err(e),
|
Err(e) => {
|
||||||
|
return ExpandResult::with_err(
|
||||||
|
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut err = None;
|
let mut err = None;
|
||||||
|
@ -666,7 +685,12 @@ fn option_env_expand(
|
||||||
) -> ExpandResult<ExpandedEager> {
|
) -> ExpandResult<ExpandedEager> {
|
||||||
let key = match parse_string(tt) {
|
let key = match parse_string(tt) {
|
||||||
Ok(it) => it,
|
Ok(it) => it,
|
||||||
Err(e) => return ExpandResult::only_err(e),
|
Err(e) => {
|
||||||
|
return ExpandResult::with_err(
|
||||||
|
ExpandedEager { subtree: tt::Subtree::empty(), included_file: None },
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let expanded = match get_env_inner(db, arg_id, &key) {
|
let expanded = match get_env_inner(db, arg_id, &key) {
|
||||||
|
|
|
@ -14,7 +14,7 @@ use syntax::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup,
|
ast_id_map::AstIdMap, builtin_attr_macro::pseudo_derive_attr_expansion, fixup,
|
||||||
hygiene::HygieneFrame, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
|
hygiene::HygieneFrame, tt, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander,
|
||||||
ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind,
|
ExpandError, ExpandResult, ExpandTo, HirFileId, HirFileIdRepr, MacroCallId, MacroCallKind,
|
||||||
MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
|
MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
|
||||||
};
|
};
|
||||||
|
@ -175,7 +175,7 @@ pub fn expand_speculative(
|
||||||
match attr.token_tree() {
|
match attr.token_tree() {
|
||||||
Some(token_tree) => {
|
Some(token_tree) => {
|
||||||
let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
|
let (mut tree, map) = syntax_node_to_token_tree(attr.token_tree()?.syntax());
|
||||||
tree.delimiter = None;
|
tree.delimiter = tt::Delimiter::unspecified();
|
||||||
|
|
||||||
let shift = mbe::Shift::new(&tt);
|
let shift = mbe::Shift::new(&tt);
|
||||||
shift.shift_all(&mut tree);
|
shift.shift_all(&mut tree);
|
||||||
|
@ -210,7 +210,7 @@ pub fn expand_speculative(
|
||||||
// Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
|
// Otherwise the expand query will fetch the non speculative attribute args and pass those instead.
|
||||||
let mut speculative_expansion = match loc.def.kind {
|
let mut speculative_expansion = match loc.def.kind {
|
||||||
MacroDefKind::ProcMacro(expander, ..) => {
|
MacroDefKind::ProcMacro(expander, ..) => {
|
||||||
tt.delimiter = None;
|
tt.delimiter = tt::Delimiter::unspecified();
|
||||||
expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
|
expander.expand(db, loc.krate, &tt, attr_arg.as_ref())
|
||||||
}
|
}
|
||||||
MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
|
MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => {
|
||||||
|
@ -316,9 +316,8 @@ fn macro_arg(
|
||||||
|
|
||||||
if loc.def.is_proc_macro() {
|
if loc.def.is_proc_macro() {
|
||||||
// proc macros expect their inputs without parentheses, MBEs expect it with them included
|
// proc macros expect their inputs without parentheses, MBEs expect it with them included
|
||||||
tt.delimiter = None;
|
tt.delimiter = tt::Delimiter::unspecified();
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Arc::new((tt, tmap, fixups.undo_info)))
|
Some(Arc::new((tt, tmap, fixups.undo_info)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,7 +478,10 @@ fn expand_proc_macro(db: &dyn AstDatabase, id: MacroCallId) -> ExpandResult<tt::
|
||||||
let macro_arg = match db.macro_arg(id) {
|
let macro_arg = match db.macro_arg(id) {
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
None => {
|
None => {
|
||||||
return ExpandResult::only_err(ExpandError::Other("No arguments for proc-macro".into()))
|
return ExpandResult::with_err(
|
||||||
|
tt::Subtree::empty(),
|
||||||
|
ExpandError::Other("No arguments for proc-macro".into()),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ pub fn expand_eager_macro(
|
||||||
.value
|
.value
|
||||||
.token_tree()
|
.token_tree()
|
||||||
.map(|tt| mbe::syntax_node_to_token_tree(tt.syntax()).0)
|
.map(|tt| mbe::syntax_node_to_token_tree(tt.syntax()).0)
|
||||||
.unwrap_or_default();
|
.unwrap_or_else(tt::Subtree::empty);
|
||||||
|
|
||||||
let ast_map = db.ast_id_map(macro_call.file_id);
|
let ast_map = db.ast_id_map(macro_call.file_id);
|
||||||
let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value));
|
let call_id = InFile::new(macro_call.file_id, ast_map.ast_id(¯o_call.value));
|
||||||
|
@ -165,9 +165,9 @@ pub fn expand_eager_macro(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_subtree(node: &SyntaxNode) -> tt::Subtree {
|
fn to_subtree(node: &SyntaxNode) -> crate::tt::Subtree {
|
||||||
let mut subtree = mbe::syntax_node_to_token_tree(node).0;
|
let mut subtree = mbe::syntax_node_to_token_tree(node).0;
|
||||||
subtree.delimiter = None;
|
subtree.delimiter = crate::tt::Delimiter::unspecified();
|
||||||
subtree
|
subtree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use syntax::{
|
||||||
ast::{self, AstNode, HasLoopBody},
|
ast::{self, AstNode, HasLoopBody},
|
||||||
match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
|
match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
|
||||||
};
|
};
|
||||||
use tt::Subtree;
|
use tt::token_id::Subtree;
|
||||||
|
|
||||||
/// The result of calculating fixes for a syntax node -- a bunch of changes
|
/// The result of calculating fixes for a syntax node -- a bunch of changes
|
||||||
/// (appending to and replacing nodes), the information that is needed to
|
/// (appending to and replacing nodes), the information that is needed to
|
||||||
|
@ -297,9 +297,11 @@ pub(crate) fn reverse_fixups(
|
||||||
tt.token_trees = tts
|
tt.token_trees = tts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|tt| match tt {
|
.filter(|tt| match tt {
|
||||||
tt::TokenTree::Leaf(leaf) => token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID),
|
tt::TokenTree::Leaf(leaf) => {
|
||||||
|
token_map.synthetic_token_id(*leaf.span()) != Some(EMPTY_ID)
|
||||||
|
}
|
||||||
tt::TokenTree::Subtree(st) => {
|
tt::TokenTree::Subtree(st) => {
|
||||||
st.delimiter.map_or(true, |d| token_map.synthetic_token_id(d.id) != Some(EMPTY_ID))
|
token_map.synthetic_token_id(st.delimiter.open) != Some(EMPTY_ID)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.flat_map(|tt| match tt {
|
.flat_map(|tt| match tt {
|
||||||
|
@ -308,9 +310,9 @@ pub(crate) fn reverse_fixups(
|
||||||
SmallVec::from_const([tt.into()])
|
SmallVec::from_const([tt.into()])
|
||||||
}
|
}
|
||||||
tt::TokenTree::Leaf(leaf) => {
|
tt::TokenTree::Leaf(leaf) => {
|
||||||
if let Some(id) = token_map.synthetic_token_id(leaf.id()) {
|
if let Some(id) = token_map.synthetic_token_id(*leaf.span()) {
|
||||||
let original = undo_info.original[id.0 as usize].clone();
|
let original = undo_info.original[id.0 as usize].clone();
|
||||||
if original.delimiter.is_none() {
|
if original.delimiter.kind == tt::DelimiterKind::Invisible {
|
||||||
original.token_trees.into()
|
original.token_trees.into()
|
||||||
} else {
|
} else {
|
||||||
SmallVec::from_const([original.into()])
|
SmallVec::from_const([original.into()])
|
||||||
|
@ -327,6 +329,8 @@ pub(crate) fn reverse_fixups(
|
||||||
mod tests {
|
mod tests {
|
||||||
use expect_test::{expect, Expect};
|
use expect_test::{expect, Expect};
|
||||||
|
|
||||||
|
use crate::tt;
|
||||||
|
|
||||||
use super::reverse_fixups;
|
use super::reverse_fixups;
|
||||||
|
|
||||||
// The following three functions are only meant to check partial structural equivalence of
|
// The following three functions are only meant to check partial structural equivalence of
|
||||||
|
@ -341,7 +345,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_subtree_eq(a: &tt::Subtree, b: &tt::Subtree) -> bool {
|
fn check_subtree_eq(a: &tt::Subtree, b: &tt::Subtree) -> bool {
|
||||||
a.delimiter.map(|it| it.kind) == b.delimiter.map(|it| it.kind)
|
a.delimiter.kind == b.delimiter.kind
|
||||||
&& a.token_trees.len() == b.token_trees.len()
|
&& a.token_trees.len() == b.token_trees.len()
|
||||||
&& a.token_trees.iter().zip(&b.token_trees).all(|(a, b)| check_tt_eq(a, b))
|
&& a.token_trees.iter().zip(&b.token_trees).all(|(a, b)| check_tt_eq(a, b))
|
||||||
}
|
}
|
||||||
|
@ -386,7 +390,7 @@ mod tests {
|
||||||
let (original_as_tt, _) = mbe::syntax_node_to_token_tree(&parsed.syntax_node());
|
let (original_as_tt, _) = mbe::syntax_node_to_token_tree(&parsed.syntax_node());
|
||||||
assert!(
|
assert!(
|
||||||
check_subtree_eq(&tt, &original_as_tt),
|
check_subtree_eq(&tt, &original_as_tt),
|
||||||
"different token tree: {tt:?}, {original_as_tt:?}"
|
"different token tree: {tt:?},\n{original_as_tt:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ struct HygieneInfo {
|
||||||
attr_input_or_mac_def_start: Option<InFile<TextSize>>,
|
attr_input_or_mac_def_start: Option<InFile<TextSize>>,
|
||||||
|
|
||||||
macro_def: Arc<TokenExpander>,
|
macro_def: Arc<TokenExpander>,
|
||||||
macro_arg: Arc<(tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
|
macro_arg: Arc<(crate::tt::Subtree, mbe::TokenMap, fixup::SyntaxFixupUndoInfo)>,
|
||||||
macro_arg_shift: mbe::Shift,
|
macro_arg_shift: mbe::Shift,
|
||||||
exp_map: Arc<mbe::TokenMap>,
|
exp_map: Arc<mbe::TokenMap>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ mod fixup;
|
||||||
|
|
||||||
pub use mbe::{Origin, ValueResult};
|
pub use mbe::{Origin, ValueResult};
|
||||||
|
|
||||||
|
use ::tt::token_id as tt;
|
||||||
|
|
||||||
use std::{fmt, hash::Hash, iter, sync::Arc};
|
use std::{fmt, hash::Hash, iter, sync::Arc};
|
||||||
|
|
||||||
use base_db::{
|
use base_db::{
|
||||||
|
|
|
@ -191,7 +191,7 @@ impl AsName for ast::NameOrNameRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsName for tt::Ident {
|
impl<Span> AsName for tt::Ident<Span> {
|
||||||
fn as_name(&self) -> Name {
|
fn as_name(&self) -> Name {
|
||||||
Name::resolve(&self.text)
|
Name::resolve(&self.text)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use base_db::{CrateId, ProcMacroExpansionError, ProcMacroId, ProcMacroKind};
|
use base_db::{CrateId, ProcMacroExpansionError, ProcMacroId, ProcMacroKind};
|
||||||
use stdx::never;
|
use stdx::never;
|
||||||
|
|
||||||
use crate::{db::AstDatabase, ExpandError, ExpandResult};
|
use crate::{db::AstDatabase, tt, ExpandError, ExpandResult};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||||
pub struct ProcMacroExpander {
|
pub struct ProcMacroExpander {
|
||||||
|
@ -39,7 +39,10 @@ impl ProcMacroExpander {
|
||||||
Ok(proc_macros) => proc_macros,
|
Ok(proc_macros) => proc_macros,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
never!("Non-dummy expander even though there are no proc macros");
|
never!("Non-dummy expander even though there are no proc macros");
|
||||||
return ExpandResult::only_err(ExpandError::Other("Internal error".into()));
|
return ExpandResult::with_err(
|
||||||
|
tt::Subtree::empty(),
|
||||||
|
ExpandError::Other("Internal error".into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let proc_macro = match proc_macros.get(id.0 as usize) {
|
let proc_macro = match proc_macros.get(id.0 as usize) {
|
||||||
|
@ -50,7 +53,10 @@ impl ProcMacroExpander {
|
||||||
proc_macros.len(),
|
proc_macros.len(),
|
||||||
id.0
|
id.0
|
||||||
);
|
);
|
||||||
return ExpandResult::only_err(ExpandError::Other("Internal error".into()));
|
return ExpandResult::with_err(
|
||||||
|
tt::Subtree::empty(),
|
||||||
|
ExpandError::Other("Internal error".into()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -69,13 +75,17 @@ impl ProcMacroExpander {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ProcMacroExpansionError::System(text)
|
ProcMacroExpansionError::System(text)
|
||||||
| ProcMacroExpansionError::Panic(text) => {
|
| ProcMacroExpansionError::Panic(text) => ExpandResult::with_err(
|
||||||
ExpandResult::only_err(ExpandError::Other(text.into()))
|
tt::Subtree::empty(),
|
||||||
}
|
ExpandError::Other(text.into()),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => ExpandResult::only_err(ExpandError::UnresolvedProcMacro(self.krate)),
|
None => ExpandResult::with_err(
|
||||||
|
tt::Subtree::empty(),
|
||||||
|
ExpandError::UnresolvedProcMacro(self.krate),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,18 @@
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! __quote {
|
macro_rules! __quote {
|
||||||
() => {
|
() => {
|
||||||
Vec::<tt::TokenTree>::new()
|
Vec::<crate::tt::TokenTree>::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
( @SUBTREE $delim:ident $($tt:tt)* ) => {
|
( @SUBTREE $delim:ident $($tt:tt)* ) => {
|
||||||
{
|
{
|
||||||
let children = $crate::__quote!($($tt)*);
|
let children = $crate::__quote!($($tt)*);
|
||||||
tt::Subtree {
|
crate::tt::Subtree {
|
||||||
delimiter: Some(tt::Delimiter {
|
delimiter: crate::tt::Delimiter {
|
||||||
kind: tt::DelimiterKind::$delim,
|
kind: crate::tt::DelimiterKind::$delim,
|
||||||
id: tt::TokenId::unspecified(),
|
open: crate::tt::TokenId::unspecified(),
|
||||||
}),
|
close: crate::tt::TokenId::unspecified(),
|
||||||
|
},
|
||||||
token_trees: $crate::quote::IntoTt::to_tokens(children),
|
token_trees: $crate::quote::IntoTt::to_tokens(children),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,10 +29,10 @@ macro_rules! __quote {
|
||||||
( @PUNCT $first:literal ) => {
|
( @PUNCT $first:literal ) => {
|
||||||
{
|
{
|
||||||
vec![
|
vec![
|
||||||
tt::Leaf::Punct(tt::Punct {
|
crate::tt::Leaf::Punct(crate::tt::Punct {
|
||||||
char: $first,
|
char: $first,
|
||||||
spacing: tt::Spacing::Alone,
|
spacing: crate::tt::Spacing::Alone,
|
||||||
id: tt::TokenId::unspecified(),
|
span: crate::tt::TokenId::unspecified(),
|
||||||
}).into()
|
}).into()
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -40,15 +41,15 @@ macro_rules! __quote {
|
||||||
( @PUNCT $first:literal, $sec:literal ) => {
|
( @PUNCT $first:literal, $sec:literal ) => {
|
||||||
{
|
{
|
||||||
vec![
|
vec![
|
||||||
tt::Leaf::Punct(tt::Punct {
|
crate::tt::Leaf::Punct(crate::tt::Punct {
|
||||||
char: $first,
|
char: $first,
|
||||||
spacing: tt::Spacing::Joint,
|
spacing: crate::tt::Spacing::Joint,
|
||||||
id: tt::TokenId::unspecified(),
|
span: crate::tt::TokenId::unspecified(),
|
||||||
}).into(),
|
}).into(),
|
||||||
tt::Leaf::Punct(tt::Punct {
|
crate::tt::Leaf::Punct(crate::tt::Punct {
|
||||||
char: $sec,
|
char: $sec,
|
||||||
spacing: tt::Spacing::Alone,
|
spacing: crate::tt::Spacing::Alone,
|
||||||
id: tt::TokenId::unspecified(),
|
span: crate::tt::TokenId::unspecified(),
|
||||||
}).into()
|
}).into()
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -67,7 +68,7 @@ macro_rules! __quote {
|
||||||
|
|
||||||
( ## $first:ident $($tail:tt)* ) => {
|
( ## $first:ident $($tail:tt)* ) => {
|
||||||
{
|
{
|
||||||
let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<tt::TokenTree>>();
|
let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<crate::tt::TokenTree>>();
|
||||||
let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
|
let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
|
||||||
tokens.append(&mut tail_tokens);
|
tokens.append(&mut tail_tokens);
|
||||||
tokens
|
tokens
|
||||||
|
@ -86,9 +87,9 @@ macro_rules! __quote {
|
||||||
// Ident
|
// Ident
|
||||||
( $tt:ident ) => {
|
( $tt:ident ) => {
|
||||||
vec![ {
|
vec![ {
|
||||||
tt::Leaf::Ident(tt::Ident {
|
crate::tt::Leaf::Ident(crate::tt::Ident {
|
||||||
text: stringify!($tt).into(),
|
text: stringify!($tt).into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: crate::tt::TokenId::unspecified(),
|
||||||
}).into()
|
}).into()
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
@ -127,42 +128,42 @@ macro_rules! quote {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait IntoTt {
|
pub(crate) trait IntoTt {
|
||||||
fn to_subtree(self) -> tt::Subtree;
|
fn to_subtree(self) -> crate::tt::Subtree;
|
||||||
fn to_tokens(self) -> Vec<tt::TokenTree>;
|
fn to_tokens(self) -> Vec<crate::tt::TokenTree>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoTt for Vec<tt::TokenTree> {
|
impl IntoTt for Vec<crate::tt::TokenTree> {
|
||||||
fn to_subtree(self) -> tt::Subtree {
|
fn to_subtree(self) -> crate::tt::Subtree {
|
||||||
tt::Subtree { delimiter: None, token_trees: self }
|
crate::tt::Subtree { delimiter: crate::tt::Delimiter::unspecified(), token_trees: self }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_tokens(self) -> Vec<tt::TokenTree> {
|
fn to_tokens(self) -> Vec<crate::tt::TokenTree> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoTt for tt::Subtree {
|
impl IntoTt for crate::tt::Subtree {
|
||||||
fn to_subtree(self) -> tt::Subtree {
|
fn to_subtree(self) -> crate::tt::Subtree {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_tokens(self) -> Vec<tt::TokenTree> {
|
fn to_tokens(self) -> Vec<crate::tt::TokenTree> {
|
||||||
vec![tt::TokenTree::Subtree(self)]
|
vec![crate::tt::TokenTree::Subtree(self)]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait ToTokenTree {
|
pub(crate) trait ToTokenTree {
|
||||||
fn to_token(self) -> tt::TokenTree;
|
fn to_token(self) -> crate::tt::TokenTree;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokenTree for tt::TokenTree {
|
impl ToTokenTree for crate::tt::TokenTree {
|
||||||
fn to_token(self) -> tt::TokenTree {
|
fn to_token(self) -> crate::tt::TokenTree {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokenTree for tt::Subtree {
|
impl ToTokenTree for crate::tt::Subtree {
|
||||||
fn to_token(self) -> tt::TokenTree {
|
fn to_token(self) -> crate::tt::TokenTree {
|
||||||
self.into()
|
self.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,15 +172,15 @@ macro_rules! impl_to_to_tokentrees {
|
||||||
($($ty:ty => $this:ident $im:block);*) => {
|
($($ty:ty => $this:ident $im:block);*) => {
|
||||||
$(
|
$(
|
||||||
impl ToTokenTree for $ty {
|
impl ToTokenTree for $ty {
|
||||||
fn to_token($this) -> tt::TokenTree {
|
fn to_token($this) -> crate::tt::TokenTree {
|
||||||
let leaf: tt::Leaf = $im.into();
|
let leaf: crate::tt::Leaf = $im.into();
|
||||||
leaf.into()
|
leaf.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokenTree for &$ty {
|
impl ToTokenTree for &$ty {
|
||||||
fn to_token($this) -> tt::TokenTree {
|
fn to_token($this) -> crate::tt::TokenTree {
|
||||||
let leaf: tt::Leaf = $im.clone().into();
|
let leaf: crate::tt::Leaf = $im.clone().into();
|
||||||
leaf.into()
|
leaf.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,16 +189,16 @@ macro_rules! impl_to_to_tokentrees {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_to_to_tokentrees! {
|
impl_to_to_tokentrees! {
|
||||||
u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
|
u32 => self { crate::tt::Literal{text: self.to_string().into(), span: crate::tt::TokenId::unspecified()} };
|
||||||
usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
|
usize => self { crate::tt::Literal{text: self.to_string().into(), span: crate::tt::TokenId::unspecified()} };
|
||||||
i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
|
i32 => self { crate::tt::Literal{text: self.to_string().into(), span: crate::tt::TokenId::unspecified()} };
|
||||||
bool => self { tt::Ident{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
|
bool => self { crate::tt::Ident{text: self.to_string().into(), span: crate::tt::TokenId::unspecified()} };
|
||||||
tt::Leaf => self { self };
|
crate::tt::Leaf => self { self };
|
||||||
tt::Literal => self { self };
|
crate::tt::Literal => self { self };
|
||||||
tt::Ident => self { self };
|
crate::tt::Ident => self { self };
|
||||||
tt::Punct => self { self };
|
crate::tt::Punct => self { self };
|
||||||
&str => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}};
|
&str => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span: crate::tt::TokenId::unspecified()}};
|
||||||
String => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}}
|
String => self { crate::tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), span: crate::tt::TokenId::unspecified()}}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -223,8 +224,8 @@ mod tests {
|
||||||
assert_eq!(quote!(#s).to_string(), "\"hello\"");
|
assert_eq!(quote!(#s).to_string(), "\"hello\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_ident(name: &str) -> tt::Ident {
|
fn mk_ident(name: &str) -> crate::tt::Ident {
|
||||||
tt::Ident { text: name.into(), id: tt::TokenId::unspecified() }
|
crate::tt::Ident { text: name.into(), span: crate::tt::TokenId::unspecified() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -234,7 +235,7 @@ mod tests {
|
||||||
let quoted = quote!(#a);
|
let quoted = quote!(#a);
|
||||||
assert_eq!(quoted.to_string(), "hello");
|
assert_eq!(quoted.to_string(), "hello");
|
||||||
let t = format!("{quoted:?}");
|
let t = format!("{quoted:?}");
|
||||||
assert_eq!(t, "SUBTREE $\n IDENT hello 4294967295");
|
assert_eq!(t, "SUBTREE $$ 4294967295 4294967295\n IDENT hello 4294967295");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -263,11 +264,12 @@ mod tests {
|
||||||
let fields = [mk_ident("name"), mk_ident("id")];
|
let fields = [mk_ident("name"), mk_ident("id")];
|
||||||
let fields = fields.iter().flat_map(|it| quote!(#it: self.#it.clone(), ).token_trees);
|
let fields = fields.iter().flat_map(|it| quote!(#it: self.#it.clone(), ).token_trees);
|
||||||
|
|
||||||
let list = tt::Subtree {
|
let list = crate::tt::Subtree {
|
||||||
delimiter: Some(tt::Delimiter {
|
delimiter: crate::tt::Delimiter {
|
||||||
kind: tt::DelimiterKind::Brace,
|
kind: crate::tt::DelimiterKind::Brace,
|
||||||
id: tt::TokenId::unspecified(),
|
open: crate::tt::TokenId::unspecified(),
|
||||||
}),
|
close: crate::tt::TokenId::unspecified(),
|
||||||
|
},
|
||||||
token_trees: fields.collect(),
|
token_trees: fields.collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use test_utils::{bench, bench_fixture, skip_slow_tests};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parser::{MetaVarKind, Op, RepeatKind, Separator},
|
parser::{MetaVarKind, Op, RepeatKind, Separator},
|
||||||
syntax_node_to_token_tree, DeclarativeMacro,
|
syntax_node_to_token_tree, tt, DeclarativeMacro,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -91,7 +91,14 @@ fn invocation_fixtures(rules: &FxHashMap<String, DeclarativeMacro>) -> Vec<(Stri
|
||||||
// So we just skip any error cases and try again
|
// So we just skip any error cases and try again
|
||||||
let mut try_cnt = 0;
|
let mut try_cnt = 0;
|
||||||
loop {
|
loop {
|
||||||
let mut subtree = tt::Subtree::default();
|
let mut subtree = tt::Subtree {
|
||||||
|
delimiter: tt::Delimiter {
|
||||||
|
open: tt::TokenId::UNSPECIFIED,
|
||||||
|
close: tt::TokenId::UNSPECIFIED,
|
||||||
|
kind: tt::DelimiterKind::Invisible,
|
||||||
|
},
|
||||||
|
token_trees: vec![],
|
||||||
|
};
|
||||||
for op in rule.lhs.iter() {
|
for op in rule.lhs.iter() {
|
||||||
collect_from_op(op, &mut subtree, &mut seed);
|
collect_from_op(op, &mut subtree, &mut seed);
|
||||||
}
|
}
|
||||||
|
@ -196,12 +203,15 @@ fn invocation_fixtures(rules: &FxHashMap<String, DeclarativeMacro>) -> Vec<(Stri
|
||||||
*seed
|
*seed
|
||||||
}
|
}
|
||||||
fn make_ident(ident: &str) -> tt::TokenTree {
|
fn make_ident(ident: &str) -> tt::TokenTree {
|
||||||
tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), text: SmolStr::new(ident) })
|
tt::Leaf::Ident(tt::Ident {
|
||||||
.into()
|
span: tt::TokenId::unspecified(),
|
||||||
|
text: SmolStr::new(ident),
|
||||||
|
})
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
fn make_punct(char: char) -> tt::TokenTree {
|
fn make_punct(char: char) -> tt::TokenTree {
|
||||||
tt::Leaf::Punct(tt::Punct {
|
tt::Leaf::Punct(tt::Punct {
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
char,
|
char,
|
||||||
spacing: tt::Spacing::Alone,
|
spacing: tt::Spacing::Alone,
|
||||||
})
|
})
|
||||||
|
@ -209,7 +219,7 @@ fn invocation_fixtures(rules: &FxHashMap<String, DeclarativeMacro>) -> Vec<(Stri
|
||||||
}
|
}
|
||||||
fn make_literal(lit: &str) -> tt::TokenTree {
|
fn make_literal(lit: &str) -> tt::TokenTree {
|
||||||
tt::Leaf::Literal(tt::Literal {
|
tt::Leaf::Literal(tt::Literal {
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
text: SmolStr::new(lit),
|
text: SmolStr::new(lit),
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
|
@ -219,7 +229,11 @@ fn invocation_fixtures(rules: &FxHashMap<String, DeclarativeMacro>) -> Vec<(Stri
|
||||||
token_trees: Option<Vec<tt::TokenTree>>,
|
token_trees: Option<Vec<tt::TokenTree>>,
|
||||||
) -> tt::TokenTree {
|
) -> tt::TokenTree {
|
||||||
tt::Subtree {
|
tt::Subtree {
|
||||||
delimiter: Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind }),
|
delimiter: tt::Delimiter {
|
||||||
|
open: tt::TokenId::unspecified(),
|
||||||
|
close: tt::TokenId::unspecified(),
|
||||||
|
kind,
|
||||||
|
},
|
||||||
token_trees: token_trees.unwrap_or_default(),
|
token_trees: token_trees.unwrap_or_default(),
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
|
|
|
@ -8,7 +8,7 @@ mod transcriber;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{parser::MetaVarKind, ExpandError, ExpandResult};
|
use crate::{parser::MetaVarKind, tt, ExpandError, ExpandResult};
|
||||||
|
|
||||||
pub(crate) fn expand_rules(
|
pub(crate) fn expand_rules(
|
||||||
rules: &[crate::Rule],
|
rules: &[crate::Rule],
|
||||||
|
@ -45,7 +45,10 @@ pub(crate) fn expand_rules(
|
||||||
transcriber::transcribe(&rule.rhs, &match_.bindings);
|
transcriber::transcribe(&rule.rhs, &match_.bindings);
|
||||||
ExpandResult { value, err: match_.err.or(transcribe_err) }
|
ExpandResult { value, err: match_.err.or(transcribe_err) }
|
||||||
} else {
|
} else {
|
||||||
ExpandResult::only_err(ExpandError::NoMatchingRule)
|
ExpandResult::with_err(
|
||||||
|
tt::Subtree { delimiter: tt::Delimiter::unspecified(), token_trees: vec![] },
|
||||||
|
ExpandError::NoMatchingRule,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ use syntax::SmolStr;
|
||||||
use crate::{
|
use crate::{
|
||||||
expander::{Binding, Bindings, ExpandResult, Fragment},
|
expander::{Binding, Bindings, ExpandResult, Fragment},
|
||||||
parser::{MetaVarKind, Op, RepeatKind, Separator},
|
parser::{MetaVarKind, Op, RepeatKind, Separator},
|
||||||
|
tt,
|
||||||
tt_iter::TtIter,
|
tt_iter::TtIter,
|
||||||
ExpandError, MetaTemplate, ValueResult,
|
ExpandError, MetaTemplate, ValueResult,
|
||||||
};
|
};
|
||||||
|
@ -75,7 +76,8 @@ impl Bindings {
|
||||||
fn push_optional(&mut self, name: &SmolStr) {
|
fn push_optional(&mut self, name: &SmolStr) {
|
||||||
// FIXME: Do we have a better way to represent an empty token ?
|
// FIXME: Do we have a better way to represent an empty token ?
|
||||||
// Insert an empty subtree for empty token
|
// Insert an empty subtree for empty token
|
||||||
let tt = tt::Subtree::default().into();
|
let tt =
|
||||||
|
tt::Subtree { delimiter: tt::Delimiter::unspecified(), token_trees: vec![] }.into();
|
||||||
self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
|
self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,9 +464,9 @@ fn match_loop_inner<'t>(
|
||||||
}
|
}
|
||||||
OpDelimited::Op(Op::Subtree { tokens, delimiter }) => {
|
OpDelimited::Op(Op::Subtree { tokens, delimiter }) => {
|
||||||
if let Ok(subtree) = src.clone().expect_subtree() {
|
if let Ok(subtree) = src.clone().expect_subtree() {
|
||||||
if subtree.delimiter_kind() == delimiter.map(|it| it.kind) {
|
if subtree.delimiter.kind == delimiter.kind {
|
||||||
item.stack.push(item.dot);
|
item.stack.push(item.dot);
|
||||||
item.dot = tokens.iter_delimited(delimiter.as_ref());
|
item.dot = tokens.iter_delimited(Some(delimiter));
|
||||||
cur_items.push(item);
|
cur_items.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -663,8 +665,8 @@ fn match_loop(pattern: &MetaTemplate, src: &tt::Subtree) -> Match {
|
||||||
}
|
}
|
||||||
res.add_err(ExpandError::LeftoverTokens);
|
res.add_err(ExpandError::LeftoverTokens);
|
||||||
|
|
||||||
if let Some(error_reover_item) = error_recover_item {
|
if let Some(error_recover_item) = error_recover_item {
|
||||||
res.bindings = bindings_builder.build(&error_reover_item);
|
res.bindings = bindings_builder.build(&error_recover_item);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -782,7 +784,7 @@ fn match_meta_var(kind: MetaVarKind, input: &mut TtIter<'_>) -> ExpandResult<Opt
|
||||||
match neg {
|
match neg {
|
||||||
None => lit.into(),
|
None => lit.into(),
|
||||||
Some(neg) => tt::TokenTree::Subtree(tt::Subtree {
|
Some(neg) => tt::TokenTree::Subtree(tt::Subtree {
|
||||||
delimiter: None,
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
token_trees: vec![neg, lit.into()],
|
token_trees: vec![neg, lit.into()],
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -810,7 +812,11 @@ fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate)
|
||||||
}
|
}
|
||||||
impl MetaTemplate {
|
impl MetaTemplate {
|
||||||
fn iter_delimited<'a>(&'a self, delimited: Option<&'a tt::Delimiter>) -> OpDelimitedIter<'a> {
|
fn iter_delimited<'a>(&'a self, delimited: Option<&'a tt::Delimiter>) -> OpDelimitedIter<'a> {
|
||||||
OpDelimitedIter { inner: &self.0, idx: 0, delimited }
|
OpDelimitedIter {
|
||||||
|
inner: &self.0,
|
||||||
|
idx: 0,
|
||||||
|
delimited: delimited.unwrap_or(&tt::Delimiter::UNSPECIFIED),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -824,20 +830,21 @@ enum OpDelimited<'a> {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct OpDelimitedIter<'a> {
|
struct OpDelimitedIter<'a> {
|
||||||
inner: &'a [Op],
|
inner: &'a [Op],
|
||||||
delimited: Option<&'a tt::Delimiter>,
|
delimited: &'a tt::Delimiter,
|
||||||
idx: usize,
|
idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> OpDelimitedIter<'a> {
|
impl<'a> OpDelimitedIter<'a> {
|
||||||
fn is_eof(&self) -> bool {
|
fn is_eof(&self) -> bool {
|
||||||
let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
|
let len = self.inner.len()
|
||||||
|
+ if self.delimited.kind != tt::DelimiterKind::Invisible { 2 } else { 0 };
|
||||||
self.idx >= len
|
self.idx >= len
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek(&self) -> Option<OpDelimited<'a>> {
|
fn peek(&self) -> Option<OpDelimited<'a>> {
|
||||||
match self.delimited {
|
match self.delimited.kind {
|
||||||
None => self.inner.get(self.idx).map(OpDelimited::Op),
|
tt::DelimiterKind::Invisible => self.inner.get(self.idx).map(OpDelimited::Op),
|
||||||
Some(_) => match self.idx {
|
_ => match self.idx {
|
||||||
0 => Some(OpDelimited::Open),
|
0 => Some(OpDelimited::Open),
|
||||||
i if i == self.inner.len() + 1 => Some(OpDelimited::Close),
|
i if i == self.inner.len() + 1 => Some(OpDelimited::Close),
|
||||||
i => self.inner.get(i - 1).map(OpDelimited::Op),
|
i => self.inner.get(i - 1).map(OpDelimited::Op),
|
||||||
|
@ -860,7 +867,8 @@ impl<'a> Iterator for OpDelimitedIter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
let len = self.inner.len() + if self.delimited.is_some() { 2 } else { 0 };
|
let len = self.inner.len()
|
||||||
|
+ if self.delimited.kind != tt::DelimiterKind::Invisible { 2 } else { 0 };
|
||||||
let remain = len.saturating_sub(self.idx);
|
let remain = len.saturating_sub(self.idx);
|
||||||
(remain, Some(remain))
|
(remain, Some(remain))
|
||||||
}
|
}
|
||||||
|
@ -904,7 +912,10 @@ impl<'a> TtIter<'a> {
|
||||||
} else {
|
} else {
|
||||||
let puncts = self.expect_glued_punct()?;
|
let puncts = self.expect_glued_punct()?;
|
||||||
let token_trees = puncts.into_iter().map(|p| tt::Leaf::Punct(p).into()).collect();
|
let token_trees = puncts.into_iter().map(|p| tt::Leaf::Punct(p).into()).collect();
|
||||||
Ok(tt::TokenTree::Subtree(tt::Subtree { delimiter: None, token_trees }))
|
Ok(tt::TokenTree::Subtree(tt::Subtree {
|
||||||
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
|
token_trees,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.next().ok_or(()).cloned()
|
self.next().ok_or(()).cloned()
|
||||||
|
@ -919,7 +930,7 @@ impl<'a> TtIter<'a> {
|
||||||
let ident = self.expect_ident_or_underscore()?;
|
let ident = self.expect_ident_or_underscore()?;
|
||||||
|
|
||||||
Ok(tt::Subtree {
|
Ok(tt::Subtree {
|
||||||
delimiter: None,
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
token_trees: vec![
|
token_trees: vec![
|
||||||
tt::Leaf::Punct(*punct).into(),
|
tt::Leaf::Punct(*punct).into(),
|
||||||
tt::Leaf::Ident(ident.clone()).into(),
|
tt::Leaf::Ident(ident.clone()).into(),
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}`
|
//! `$ident => foo`, interpolates variables in the template, to get `fn foo() {}`
|
||||||
|
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
use tt::{Delimiter, Subtree};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
expander::{Binding, Bindings, Fragment},
|
expander::{Binding, Bindings, Fragment},
|
||||||
parser::{MetaVarKind, Op, RepeatKind, Separator},
|
parser::{MetaVarKind, Op, RepeatKind, Separator},
|
||||||
|
tt::{self, Delimiter},
|
||||||
ExpandError, ExpandResult, MetaTemplate,
|
ExpandError, ExpandResult, MetaTemplate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,22 +44,23 @@ impl Bindings {
|
||||||
Binding::Missing(it) => Ok(match it {
|
Binding::Missing(it) => Ok(match it {
|
||||||
MetaVarKind::Stmt => {
|
MetaVarKind::Stmt => {
|
||||||
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
|
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
char: ';',
|
char: ';',
|
||||||
spacing: tt::Spacing::Alone,
|
spacing: tt::Spacing::Alone,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
MetaVarKind::Block => Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
|
MetaVarKind::Block => Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
|
||||||
delimiter: Some(tt::Delimiter {
|
delimiter: tt::Delimiter {
|
||||||
id: tt::TokenId::unspecified(),
|
open: tt::TokenId::unspecified(),
|
||||||
|
close: tt::TokenId::unspecified(),
|
||||||
kind: tt::DelimiterKind::Brace,
|
kind: tt::DelimiterKind::Brace,
|
||||||
}),
|
},
|
||||||
token_trees: vec![],
|
token_trees: vec![],
|
||||||
})),
|
})),
|
||||||
// FIXME: Meta and Item should get proper defaults
|
// FIXME: Meta and Item should get proper defaults
|
||||||
MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => {
|
MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => {
|
||||||
Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
|
Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
|
||||||
delimiter: None,
|
delimiter: tt::Delimiter::UNSPECIFIED,
|
||||||
token_trees: vec![],
|
token_trees: vec![],
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -71,19 +72,19 @@ impl Bindings {
|
||||||
| MetaVarKind::Ident => {
|
| MetaVarKind::Ident => {
|
||||||
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: SmolStr::new_inline("missing"),
|
text: SmolStr::new_inline("missing"),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
MetaVarKind::Lifetime => {
|
MetaVarKind::Lifetime => {
|
||||||
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: SmolStr::new_inline("'missing"),
|
text: SmolStr::new_inline("'missing"),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
MetaVarKind::Literal => {
|
MetaVarKind::Literal => {
|
||||||
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: SmolStr::new_inline("\"missing\""),
|
text: SmolStr::new_inline("\"missing\""),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -143,7 +144,7 @@ fn expand_subtree(
|
||||||
}
|
}
|
||||||
Op::Subtree { tokens, delimiter } => {
|
Op::Subtree { tokens, delimiter } => {
|
||||||
let ExpandResult { value: tt, err: e } =
|
let ExpandResult { value: tt, err: e } =
|
||||||
expand_subtree(ctx, tokens, *delimiter, arena);
|
expand_subtree(ctx, tokens, Some(*delimiter), arena);
|
||||||
err = err.or(e);
|
err = err.or(e);
|
||||||
arena.push(tt.into());
|
arena.push(tt.into());
|
||||||
}
|
}
|
||||||
|
@ -170,7 +171,7 @@ fn expand_subtree(
|
||||||
arena.push(
|
arena.push(
|
||||||
tt::Leaf::Literal(tt::Literal {
|
tt::Leaf::Literal(tt::Literal {
|
||||||
text: index.to_string().into(),
|
text: index.to_string().into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
})
|
})
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
@ -179,7 +180,13 @@ fn expand_subtree(
|
||||||
}
|
}
|
||||||
// drain the elements added in this instance of expand_subtree
|
// drain the elements added in this instance of expand_subtree
|
||||||
let tts = arena.drain(start_elements..).collect();
|
let tts = arena.drain(start_elements..).collect();
|
||||||
ExpandResult { value: tt::Subtree { delimiter, token_trees: tts }, err }
|
ExpandResult {
|
||||||
|
value: tt::Subtree {
|
||||||
|
delimiter: delimiter.unwrap_or_else(tt::Delimiter::unspecified),
|
||||||
|
token_trees: tts,
|
||||||
|
},
|
||||||
|
err,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_var(ctx: &mut ExpandCtx<'_>, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> {
|
fn expand_var(ctx: &mut ExpandCtx<'_>, v: &SmolStr, id: tt::TokenId) -> ExpandResult<Fragment> {
|
||||||
|
@ -201,17 +208,24 @@ fn expand_var(ctx: &mut ExpandCtx<'_>, v: &SmolStr, id: tt::TokenId) -> ExpandRe
|
||||||
// ```
|
// ```
|
||||||
// We just treat it a normal tokens
|
// We just treat it a normal tokens
|
||||||
let tt = tt::Subtree {
|
let tt = tt::Subtree {
|
||||||
delimiter: None,
|
delimiter: tt::Delimiter::UNSPECIFIED,
|
||||||
token_trees: vec![
|
token_trees: vec![
|
||||||
tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, id }).into(),
|
tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, span: id })
|
||||||
tt::Leaf::from(tt::Ident { text: v.clone(), id }).into(),
|
.into(),
|
||||||
|
tt::Leaf::from(tt::Ident { text: v.clone(), span: id }).into(),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
.into();
|
.into();
|
||||||
ExpandResult::ok(Fragment::Tokens(tt))
|
ExpandResult::ok(Fragment::Tokens(tt))
|
||||||
} else {
|
} else {
|
||||||
ctx.bindings.get(v, &mut ctx.nesting).map_or_else(
|
ctx.bindings.get(v, &mut ctx.nesting).map_or_else(
|
||||||
|e| ExpandResult { value: Fragment::Tokens(tt::TokenTree::empty()), err: Some(e) },
|
|e| ExpandResult {
|
||||||
|
value: Fragment::Tokens(tt::TokenTree::Subtree(tt::Subtree {
|
||||||
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
|
token_trees: vec![],
|
||||||
|
})),
|
||||||
|
err: Some(e),
|
||||||
|
},
|
||||||
ExpandResult::ok,
|
ExpandResult::ok,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -249,7 +263,10 @@ fn expand_repeat(
|
||||||
ctx
|
ctx
|
||||||
);
|
);
|
||||||
return ExpandResult {
|
return ExpandResult {
|
||||||
value: Fragment::Tokens(Subtree::default().into()),
|
value: Fragment::Tokens(
|
||||||
|
tt::Subtree { delimiter: tt::Delimiter::unspecified(), token_trees: vec![] }
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
err: Some(ExpandError::LimitExceeded),
|
err: Some(ExpandError::LimitExceeded),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -258,7 +275,7 @@ fn expand_repeat(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
t.delimiter = None;
|
t.delimiter = tt::Delimiter::unspecified();
|
||||||
push_subtree(&mut buf, t);
|
push_subtree(&mut buf, t);
|
||||||
|
|
||||||
if let Some(sep) = separator {
|
if let Some(sep) = separator {
|
||||||
|
@ -292,7 +309,7 @@ fn expand_repeat(
|
||||||
|
|
||||||
// Check if it is a single token subtree without any delimiter
|
// Check if it is a single token subtree without any delimiter
|
||||||
// e.g {Delimiter:None> ['>'] /Delimiter:None>}
|
// e.g {Delimiter:None> ['>'] /Delimiter:None>}
|
||||||
let tt = tt::Subtree { delimiter: None, token_trees: buf }.into();
|
let tt = tt::Subtree { delimiter: tt::Delimiter::unspecified(), token_trees: buf }.into();
|
||||||
|
|
||||||
if RepeatKind::OneOrMore == kind && counter == 0 {
|
if RepeatKind::OneOrMore == kind && counter == 0 {
|
||||||
return ExpandResult {
|
return ExpandResult {
|
||||||
|
@ -307,11 +324,12 @@ fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
|
||||||
match fragment {
|
match fragment {
|
||||||
Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
|
Fragment::Tokens(tt::TokenTree::Subtree(tt)) => push_subtree(buf, tt),
|
||||||
Fragment::Expr(tt::TokenTree::Subtree(mut tt)) => {
|
Fragment::Expr(tt::TokenTree::Subtree(mut tt)) => {
|
||||||
if tt.delimiter.is_none() {
|
if tt.delimiter.kind == tt::DelimiterKind::Invisible {
|
||||||
tt.delimiter = Some(tt::Delimiter {
|
tt.delimiter = tt::Delimiter {
|
||||||
id: tt::TokenId::unspecified(),
|
open: tt::TokenId::UNSPECIFIED,
|
||||||
|
close: tt::TokenId::UNSPECIFIED,
|
||||||
kind: tt::DelimiterKind::Parenthesis,
|
kind: tt::DelimiterKind::Parenthesis,
|
||||||
})
|
};
|
||||||
}
|
}
|
||||||
buf.push(tt.into())
|
buf.push(tt.into())
|
||||||
}
|
}
|
||||||
|
@ -320,8 +338,8 @@ fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
|
fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
|
||||||
match tt.delimiter {
|
match tt.delimiter.kind {
|
||||||
None => buf.extend(tt.token_trees),
|
tt::DelimiterKind::Invisible => buf.extend(tt.token_trees),
|
||||||
Some(_) => buf.push(tt.into()),
|
_ => buf.push(tt.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ mod to_parser_input;
|
||||||
mod benchmark;
|
mod benchmark;
|
||||||
mod token_map;
|
mod token_map;
|
||||||
|
|
||||||
|
use ::tt::token_id as tt;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -26,8 +28,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: we probably should re-think `token_tree_to_syntax_node` interfaces
|
// FIXME: we probably should re-think `token_tree_to_syntax_node` interfaces
|
||||||
|
pub use self::tt::{Delimiter, DelimiterKind, Punct};
|
||||||
pub use ::parser::TopEntryPoint;
|
pub use ::parser::TopEntryPoint;
|
||||||
pub use tt::{Delimiter, DelimiterKind, Punct};
|
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
syntax_bridge::{
|
syntax_bridge::{
|
||||||
|
@ -125,24 +127,26 @@ impl Shift {
|
||||||
|
|
||||||
// Find the max token id inside a subtree
|
// Find the max token id inside a subtree
|
||||||
fn max_id(subtree: &tt::Subtree) -> Option<u32> {
|
fn max_id(subtree: &tt::Subtree) -> Option<u32> {
|
||||||
let filter = |tt: &_| match tt {
|
let filter =
|
||||||
tt::TokenTree::Subtree(subtree) => {
|
|tt: &_| match tt {
|
||||||
let tree_id = max_id(subtree);
|
tt::TokenTree::Subtree(subtree) => {
|
||||||
match subtree.delimiter {
|
let tree_id = max_id(subtree);
|
||||||
Some(it) if it.id != tt::TokenId::unspecified() => {
|
if subtree.delimiter.open != tt::TokenId::unspecified() {
|
||||||
Some(tree_id.map_or(it.id.0, |t| t.max(it.id.0)))
|
Some(tree_id.map_or(subtree.delimiter.open.0, |t| {
|
||||||
|
t.max(subtree.delimiter.open.0)
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
tree_id
|
||||||
}
|
}
|
||||||
_ => tree_id,
|
|
||||||
}
|
}
|
||||||
}
|
tt::TokenTree::Leaf(leaf) => {
|
||||||
tt::TokenTree::Leaf(leaf) => {
|
let &(tt::Leaf::Ident(tt::Ident { span, .. })
|
||||||
let &(tt::Leaf::Ident(tt::Ident { id, .. })
|
| tt::Leaf::Punct(tt::Punct { span, .. })
|
||||||
| tt::Leaf::Punct(tt::Punct { id, .. })
|
| tt::Leaf::Literal(tt::Literal { span, .. })) = leaf;
|
||||||
| tt::Leaf::Literal(tt::Literal { id, .. })) = leaf;
|
|
||||||
|
|
||||||
(id != tt::TokenId::unspecified()).then_some(id.0)
|
(span != tt::TokenId::unspecified()).then_some(span.0)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
subtree.token_trees.iter().filter_map(filter).max()
|
subtree.token_trees.iter().filter_map(filter).max()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,14 +156,13 @@ impl Shift {
|
||||||
for t in &mut tt.token_trees {
|
for t in &mut tt.token_trees {
|
||||||
match t {
|
match t {
|
||||||
tt::TokenTree::Leaf(
|
tt::TokenTree::Leaf(
|
||||||
tt::Leaf::Ident(tt::Ident { id, .. })
|
tt::Leaf::Ident(tt::Ident { span, .. })
|
||||||
| tt::Leaf::Punct(tt::Punct { id, .. })
|
| tt::Leaf::Punct(tt::Punct { span, .. })
|
||||||
| tt::Leaf::Literal(tt::Literal { id, .. }),
|
| tt::Leaf::Literal(tt::Literal { span, .. }),
|
||||||
) => *id = self.shift(*id),
|
) => *span = self.shift(*span),
|
||||||
tt::TokenTree::Subtree(tt) => {
|
tt::TokenTree::Subtree(tt) => {
|
||||||
if let Some(it) = tt.delimiter.as_mut() {
|
tt.delimiter.open = self.shift(tt.delimiter.open);
|
||||||
it.id = self.shift(it.id);
|
tt.delimiter.close = self.shift(tt.delimiter.close);
|
||||||
}
|
|
||||||
self.shift_all(tt)
|
self.shift_all(tt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,7 +219,7 @@ impl DeclarativeMacro {
|
||||||
let mut src = TtIter::new(tt);
|
let mut src = TtIter::new(tt);
|
||||||
let mut rules = Vec::new();
|
let mut rules = Vec::new();
|
||||||
|
|
||||||
if Some(tt::DelimiterKind::Brace) == tt.delimiter_kind() {
|
if tt::DelimiterKind::Brace == tt.delimiter.kind {
|
||||||
cov_mark::hit!(parse_macro_def_rules);
|
cov_mark::hit!(parse_macro_def_rules);
|
||||||
while src.len() > 0 {
|
while src.len() > 0 {
|
||||||
let rule = Rule::parse(&mut src, true)?;
|
let rule = Rule::parse(&mut src, true)?;
|
||||||
|
@ -325,6 +328,10 @@ impl<T, E> ValueResult<T, E> {
|
||||||
Self { value, err: None }
|
Self { value, err: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_err(value: T, err: E) -> Self {
|
||||||
|
Self { value, err: Some(err) }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn only_err(err: E) -> Self
|
pub fn only_err(err: E) -> Self
|
||||||
where
|
where
|
||||||
T: Default,
|
T: Default,
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
|
|
||||||
use crate::{tt_iter::TtIter, ParseError};
|
use crate::{tt, tt_iter::TtIter, ParseError};
|
||||||
|
|
||||||
/// Consider
|
/// Consider
|
||||||
///
|
///
|
||||||
|
@ -54,7 +54,7 @@ pub(crate) enum Op {
|
||||||
Ignore { name: SmolStr, id: tt::TokenId },
|
Ignore { name: SmolStr, id: tt::TokenId },
|
||||||
Index { depth: u32 },
|
Index { depth: u32 },
|
||||||
Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
|
Repeat { tokens: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
|
||||||
Subtree { tokens: MetaTemplate, delimiter: Option<tt::Delimiter> },
|
Subtree { tokens: MetaTemplate, delimiter: tt::Delimiter },
|
||||||
Literal(tt::Literal),
|
Literal(tt::Literal),
|
||||||
Punct(SmallVec<[tt::Punct; 3]>),
|
Punct(SmallVec<[tt::Punct; 3]>),
|
||||||
Ident(tt::Ident),
|
Ident(tt::Ident),
|
||||||
|
@ -130,13 +130,13 @@ fn next_op(
|
||||||
Some(it) => it,
|
Some(it) => it,
|
||||||
};
|
};
|
||||||
match second {
|
match second {
|
||||||
tt::TokenTree::Subtree(subtree) => match subtree.delimiter_kind() {
|
tt::TokenTree::Subtree(subtree) => match subtree.delimiter.kind {
|
||||||
Some(tt::DelimiterKind::Parenthesis) => {
|
tt::DelimiterKind::Parenthesis => {
|
||||||
let (separator, kind) = parse_repeat(src)?;
|
let (separator, kind) = parse_repeat(src)?;
|
||||||
let tokens = MetaTemplate::parse(subtree, mode)?;
|
let tokens = MetaTemplate::parse(subtree, mode)?;
|
||||||
Op::Repeat { tokens, separator, kind }
|
Op::Repeat { tokens, separator, kind }
|
||||||
}
|
}
|
||||||
Some(tt::DelimiterKind::Brace) => match mode {
|
tt::DelimiterKind::Brace => match mode {
|
||||||
Mode::Template => {
|
Mode::Template => {
|
||||||
parse_metavar_expr(&mut TtIter::new(subtree)).map_err(|()| {
|
parse_metavar_expr(&mut TtIter::new(subtree)).map_err(|()| {
|
||||||
ParseError::unexpected("invalid metavariable expression")
|
ParseError::unexpected("invalid metavariable expression")
|
||||||
|
@ -157,18 +157,18 @@ fn next_op(
|
||||||
tt::TokenTree::Leaf(leaf) => match leaf {
|
tt::TokenTree::Leaf(leaf) => match leaf {
|
||||||
tt::Leaf::Ident(ident) if ident.text == "crate" => {
|
tt::Leaf::Ident(ident) if ident.text == "crate" => {
|
||||||
// We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
|
// We simply produce identifier `$crate` here. And it will be resolved when lowering ast to Path.
|
||||||
Op::Ident(tt::Ident { text: "$crate".into(), id: ident.id })
|
Op::Ident(tt::Ident { text: "$crate".into(), span: ident.span })
|
||||||
}
|
}
|
||||||
tt::Leaf::Ident(ident) => {
|
tt::Leaf::Ident(ident) => {
|
||||||
let kind = eat_fragment_kind(src, mode)?;
|
let kind = eat_fragment_kind(src, mode)?;
|
||||||
let name = ident.text.clone();
|
let name = ident.text.clone();
|
||||||
let id = ident.id;
|
let id = ident.span;
|
||||||
Op::Var { name, kind, id }
|
Op::Var { name, kind, id }
|
||||||
}
|
}
|
||||||
tt::Leaf::Literal(lit) if is_boolean_literal(lit) => {
|
tt::Leaf::Literal(lit) if is_boolean_literal(lit) => {
|
||||||
let kind = eat_fragment_kind(src, mode)?;
|
let kind = eat_fragment_kind(src, mode)?;
|
||||||
let name = lit.text.clone();
|
let name = lit.text.clone();
|
||||||
let id = lit.id;
|
let id = lit.span;
|
||||||
Op::Var { name, kind, id }
|
Op::Var { name, kind, id }
|
||||||
}
|
}
|
||||||
tt::Leaf::Punct(punct @ tt::Punct { char: '$', .. }) => match mode {
|
tt::Leaf::Punct(punct @ tt::Punct { char: '$', .. }) => match mode {
|
||||||
|
@ -284,7 +284,7 @@ fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result<Op, ()> {
|
||||||
let func = src.expect_ident()?;
|
let func = src.expect_ident()?;
|
||||||
let args = src.expect_subtree()?;
|
let args = src.expect_subtree()?;
|
||||||
|
|
||||||
if args.delimiter_kind() != Some(tt::DelimiterKind::Parenthesis) {
|
if args.delimiter.kind != tt::DelimiterKind::Parenthesis {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result<Op, ()> {
|
||||||
let op = match &*func.text {
|
let op = match &*func.text {
|
||||||
"ignore" => {
|
"ignore" => {
|
||||||
let ident = args.expect_ident()?;
|
let ident = args.expect_ident()?;
|
||||||
Op::Ignore { name: ident.text.clone(), id: ident.id }
|
Op::Ignore { name: ident.text.clone(), id: ident.span }
|
||||||
}
|
}
|
||||||
"index" => {
|
"index" => {
|
||||||
let depth = if args.len() == 0 { 0 } else { args.expect_u32_literal()? };
|
let depth = if args.len() == 0 { 0 } else { args.expect_u32_literal()? };
|
||||||
|
|
|
@ -8,9 +8,16 @@ use syntax::{
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T,
|
SyntaxNode, SyntaxToken, SyntaxTreeBuilder, TextRange, TextSize, WalkEvent, T,
|
||||||
};
|
};
|
||||||
use tt::buffer::{Cursor, TokenBuffer};
|
|
||||||
|
|
||||||
use crate::{to_parser_input::to_parser_input, tt_iter::TtIter, TokenMap};
|
use crate::{
|
||||||
|
to_parser_input::to_parser_input,
|
||||||
|
tt::{
|
||||||
|
self,
|
||||||
|
buffer::{Cursor, TokenBuffer},
|
||||||
|
},
|
||||||
|
tt_iter::TtIter,
|
||||||
|
TokenMap,
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -74,9 +81,10 @@ pub fn token_tree_to_syntax_node(
|
||||||
entry_point: parser::TopEntryPoint,
|
entry_point: parser::TopEntryPoint,
|
||||||
) -> (Parse<SyntaxNode>, TokenMap) {
|
) -> (Parse<SyntaxNode>, TokenMap) {
|
||||||
let buffer = match tt {
|
let buffer = match tt {
|
||||||
tt::Subtree { delimiter: None, token_trees } => {
|
tt::Subtree {
|
||||||
TokenBuffer::from_tokens(token_trees.as_slice())
|
delimiter: tt::Delimiter { kind: tt::DelimiterKind::Invisible, .. },
|
||||||
}
|
token_trees,
|
||||||
|
} => TokenBuffer::from_tokens(token_trees.as_slice()),
|
||||||
_ => TokenBuffer::from_subtree(tt),
|
_ => TokenBuffer::from_subtree(tt),
|
||||||
};
|
};
|
||||||
let parser_input = to_parser_input(&buffer);
|
let parser_input = to_parser_input(&buffer);
|
||||||
|
@ -92,8 +100,7 @@ pub fn token_tree_to_syntax_node(
|
||||||
parser::Step::Error { msg } => tree_sink.error(msg.to_string()),
|
parser::Step::Error { msg } => tree_sink.error(msg.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (parse, range_map) = tree_sink.finish();
|
tree_sink.finish()
|
||||||
(parse, range_map)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a string to a `TokenTree`
|
/// Convert a string to a `TokenTree`
|
||||||
|
@ -132,7 +139,7 @@ pub fn parse_exprs_with_sep(tt: &tt::Subtree, sep: char) -> Vec<tt::Subtree> {
|
||||||
res.push(match expanded.value {
|
res.push(match expanded.value {
|
||||||
None => break,
|
None => break,
|
||||||
Some(tt @ tt::TokenTree::Leaf(_)) => {
|
Some(tt @ tt::TokenTree::Leaf(_)) => {
|
||||||
tt::Subtree { delimiter: None, token_trees: vec![tt] }
|
tt::Subtree { delimiter: tt::Delimiter::unspecified(), token_trees: vec![tt] }
|
||||||
}
|
}
|
||||||
Some(tt::TokenTree::Subtree(tt)) => tt,
|
Some(tt::TokenTree::Subtree(tt)) => tt,
|
||||||
});
|
});
|
||||||
|
@ -145,7 +152,10 @@ pub fn parse_exprs_with_sep(tt: &tt::Subtree, sep: char) -> Vec<tt::Subtree> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if iter.peek_n(0).is_some() {
|
if iter.peek_n(0).is_some() {
|
||||||
res.push(tt::Subtree { delimiter: None, token_trees: iter.cloned().collect() });
|
res.push(tt::Subtree {
|
||||||
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
|
token_trees: iter.cloned().collect(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
res
|
res
|
||||||
|
@ -159,7 +169,7 @@ fn convert_tokens<C: TokenConverter>(conv: &mut C) -> tt::Subtree {
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = StackEntry {
|
let entry = StackEntry {
|
||||||
subtree: tt::Subtree { delimiter: None, ..Default::default() },
|
subtree: tt::Subtree { delimiter: tt::Delimiter::unspecified(), token_trees: vec![] },
|
||||||
// never used (delimiter is `None`)
|
// never used (delimiter is `None`)
|
||||||
idx: !0,
|
idx: !0,
|
||||||
open_range: TextRange::empty(TextSize::of('.')),
|
open_range: TextRange::empty(TextSize::of('.')),
|
||||||
|
@ -186,7 +196,7 @@ fn convert_tokens<C: TokenConverter>(conv: &mut C) -> tt::Subtree {
|
||||||
if let Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) =
|
if let Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) =
|
||||||
sub.token_trees.get_mut(2)
|
sub.token_trees.get_mut(2)
|
||||||
{
|
{
|
||||||
lit.id = id
|
lit.span = id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tt
|
tt
|
||||||
|
@ -199,13 +209,14 @@ fn convert_tokens<C: TokenConverter>(conv: &mut C) -> tt::Subtree {
|
||||||
assert_eq!(range.len(), TextSize::of('.'));
|
assert_eq!(range.len(), TextSize::of('.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(delim) = subtree.delimiter {
|
let expected = match subtree.delimiter.kind {
|
||||||
let expected = match delim.kind {
|
tt::DelimiterKind::Parenthesis => Some(T![')']),
|
||||||
tt::DelimiterKind::Parenthesis => T![')'],
|
tt::DelimiterKind::Brace => Some(T!['}']),
|
||||||
tt::DelimiterKind::Brace => T!['}'],
|
tt::DelimiterKind::Bracket => Some(T![']']),
|
||||||
tt::DelimiterKind::Bracket => T![']'],
|
tt::DelimiterKind::Invisible => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(expected) = expected {
|
||||||
if kind == expected {
|
if kind == expected {
|
||||||
if let Some(entry) = stack.pop() {
|
if let Some(entry) = stack.pop() {
|
||||||
conv.id_alloc().close_delim(entry.idx, Some(range));
|
conv.id_alloc().close_delim(entry.idx, Some(range));
|
||||||
|
@ -223,9 +234,11 @@ fn convert_tokens<C: TokenConverter>(conv: &mut C) -> tt::Subtree {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(kind) = delim {
|
if let Some(kind) = delim {
|
||||||
let mut subtree = tt::Subtree::default();
|
|
||||||
let (id, idx) = conv.id_alloc().open_delim(range, synth_id);
|
let (id, idx) = conv.id_alloc().open_delim(range, synth_id);
|
||||||
subtree.delimiter = Some(tt::Delimiter { id, kind });
|
let subtree = tt::Subtree {
|
||||||
|
delimiter: tt::Delimiter { open: id, close: tt::TokenId::UNSPECIFIED, kind },
|
||||||
|
token_trees: vec![],
|
||||||
|
};
|
||||||
stack.push(StackEntry { subtree, idx, open_range: range });
|
stack.push(StackEntry { subtree, idx, open_range: range });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -240,13 +253,20 @@ fn convert_tokens<C: TokenConverter>(conv: &mut C) -> tt::Subtree {
|
||||||
panic!("Token from lexer must be single char: token = {token:#?}");
|
panic!("Token from lexer must be single char: token = {token:#?}");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
tt::Leaf::from(tt::Punct { char, spacing, id: conv.id_alloc().alloc(range, synth_id) })
|
tt::Leaf::from(tt::Punct {
|
||||||
.into()
|
char,
|
||||||
|
spacing,
|
||||||
|
span: conv.id_alloc().alloc(range, synth_id),
|
||||||
|
})
|
||||||
|
.into()
|
||||||
} else {
|
} else {
|
||||||
macro_rules! make_leaf {
|
macro_rules! make_leaf {
|
||||||
($i:ident) => {
|
($i:ident) => {
|
||||||
tt::$i { id: conv.id_alloc().alloc(range, synth_id), text: token.to_text(conv) }
|
tt::$i {
|
||||||
.into()
|
span: conv.id_alloc().alloc(range, synth_id),
|
||||||
|
text: token.to_text(conv),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let leaf: tt::Leaf = match kind {
|
let leaf: tt::Leaf = match kind {
|
||||||
|
@ -261,14 +281,14 @@ fn convert_tokens<C: TokenConverter>(conv: &mut C) -> tt::Subtree {
|
||||||
let apostrophe = tt::Leaf::from(tt::Punct {
|
let apostrophe = tt::Leaf::from(tt::Punct {
|
||||||
char: '\'',
|
char: '\'',
|
||||||
spacing: tt::Spacing::Joint,
|
spacing: tt::Spacing::Joint,
|
||||||
id: conv.id_alloc().alloc(r, synth_id),
|
span: conv.id_alloc().alloc(r, synth_id),
|
||||||
});
|
});
|
||||||
result.push(apostrophe.into());
|
result.push(apostrophe.into());
|
||||||
|
|
||||||
let r = TextRange::at(range.start() + char_unit, range.len() - char_unit);
|
let r = TextRange::at(range.start() + char_unit, range.len() - char_unit);
|
||||||
let ident = tt::Leaf::from(tt::Ident {
|
let ident = tt::Leaf::from(tt::Ident {
|
||||||
text: SmolStr::new(&token.to_text(conv)[1..]),
|
text: SmolStr::new(&token.to_text(conv)[1..]),
|
||||||
id: conv.id_alloc().alloc(r, synth_id),
|
span: conv.id_alloc().alloc(r, synth_id),
|
||||||
});
|
});
|
||||||
result.push(ident.into());
|
result.push(ident.into());
|
||||||
continue;
|
continue;
|
||||||
|
@ -289,11 +309,12 @@ fn convert_tokens<C: TokenConverter>(conv: &mut C) -> tt::Subtree {
|
||||||
|
|
||||||
conv.id_alloc().close_delim(entry.idx, None);
|
conv.id_alloc().close_delim(entry.idx, None);
|
||||||
let leaf: tt::Leaf = tt::Punct {
|
let leaf: tt::Leaf = tt::Punct {
|
||||||
id: conv.id_alloc().alloc(entry.open_range, None),
|
span: conv.id_alloc().alloc(entry.open_range, None),
|
||||||
char: match entry.subtree.delimiter.unwrap().kind {
|
char: match entry.subtree.delimiter.kind {
|
||||||
tt::DelimiterKind::Parenthesis => '(',
|
tt::DelimiterKind::Parenthesis => '(',
|
||||||
tt::DelimiterKind::Brace => '{',
|
tt::DelimiterKind::Brace => '{',
|
||||||
tt::DelimiterKind::Bracket => '[',
|
tt::DelimiterKind::Bracket => '[',
|
||||||
|
tt::DelimiterKind::Invisible => '$',
|
||||||
},
|
},
|
||||||
spacing: tt::Spacing::Alone,
|
spacing: tt::Spacing::Alone,
|
||||||
}
|
}
|
||||||
|
@ -373,10 +394,11 @@ fn convert_doc_comment(token: &syntax::SyntaxToken) -> Option<Vec<tt::TokenTree>
|
||||||
token_trees.push(mk_punct('!'));
|
token_trees.push(mk_punct('!'));
|
||||||
}
|
}
|
||||||
token_trees.push(tt::TokenTree::from(tt::Subtree {
|
token_trees.push(tt::TokenTree::from(tt::Subtree {
|
||||||
delimiter: Some(tt::Delimiter {
|
delimiter: tt::Delimiter {
|
||||||
|
open: tt::TokenId::UNSPECIFIED,
|
||||||
|
close: tt::TokenId::UNSPECIFIED,
|
||||||
kind: tt::DelimiterKind::Bracket,
|
kind: tt::DelimiterKind::Bracket,
|
||||||
id: tt::TokenId::unspecified(),
|
},
|
||||||
}),
|
|
||||||
token_trees: meta_tkns,
|
token_trees: meta_tkns,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -386,7 +408,7 @@ fn convert_doc_comment(token: &syntax::SyntaxToken) -> Option<Vec<tt::TokenTree>
|
||||||
fn mk_ident(s: &str) -> tt::TokenTree {
|
fn mk_ident(s: &str) -> tt::TokenTree {
|
||||||
tt::TokenTree::from(tt::Leaf::from(tt::Ident {
|
tt::TokenTree::from(tt::Leaf::from(tt::Ident {
|
||||||
text: s.into(),
|
text: s.into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,12 +416,12 @@ fn convert_doc_comment(token: &syntax::SyntaxToken) -> Option<Vec<tt::TokenTree>
|
||||||
tt::TokenTree::from(tt::Leaf::from(tt::Punct {
|
tt::TokenTree::from(tt::Leaf::from(tt::Punct {
|
||||||
char: c,
|
char: c,
|
||||||
spacing: tt::Spacing::Alone,
|
spacing: tt::Spacing::Alone,
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree {
|
fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree {
|
||||||
let lit = tt::Literal { text: doc_comment_text(comment), id: tt::TokenId::unspecified() };
|
let lit = tt::Literal { text: doc_comment_text(comment), span: tt::TokenId::unspecified() };
|
||||||
|
|
||||||
tt::TokenTree::from(tt::Leaf::from(lit))
|
tt::TokenTree::from(tt::Leaf::from(lit))
|
||||||
}
|
}
|
||||||
|
@ -761,15 +783,16 @@ impl<'a> TtTreeSink<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> &'static str {
|
fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> Option<&'static str> {
|
||||||
let texts = match d {
|
let texts = match d {
|
||||||
tt::DelimiterKind::Parenthesis => "()",
|
tt::DelimiterKind::Parenthesis => "()",
|
||||||
tt::DelimiterKind::Brace => "{}",
|
tt::DelimiterKind::Brace => "{}",
|
||||||
tt::DelimiterKind::Bracket => "[]",
|
tt::DelimiterKind::Bracket => "[]",
|
||||||
|
tt::DelimiterKind::Invisible => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let idx = closing as usize;
|
let idx = closing as usize;
|
||||||
&texts[idx..texts.len() - (1 - idx)]
|
Some(&texts[idx..texts.len() - (1 - idx)])
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TtTreeSink<'a> {
|
impl<'a> TtTreeSink<'a> {
|
||||||
|
@ -790,13 +813,16 @@ impl<'a> TtTreeSink<'a> {
|
||||||
Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => {
|
Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => {
|
||||||
// Mark the range if needed
|
// Mark the range if needed
|
||||||
let (text, id) = match leaf {
|
let (text, id) = match leaf {
|
||||||
tt::Leaf::Ident(ident) => (ident.text.as_str(), ident.id),
|
tt::Leaf::Ident(ident) => (ident.text.as_str(), ident.span),
|
||||||
tt::Leaf::Punct(punct) => {
|
tt::Leaf::Punct(punct) => {
|
||||||
assert!(punct.char.is_ascii());
|
assert!(punct.char.is_ascii());
|
||||||
tmp = punct.char as u8;
|
tmp = punct.char as u8;
|
||||||
(std::str::from_utf8(std::slice::from_ref(&tmp)).unwrap(), punct.id)
|
(
|
||||||
|
std::str::from_utf8(std::slice::from_ref(&tmp)).unwrap(),
|
||||||
|
punct.span,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
tt::Leaf::Literal(lit) => (lit.text.as_str(), lit.id),
|
tt::Leaf::Literal(lit) => (lit.text.as_str(), lit.span),
|
||||||
};
|
};
|
||||||
let range = TextRange::at(self.text_pos, TextSize::of(text));
|
let range = TextRange::at(self.text_pos, TextSize::of(text));
|
||||||
self.token_map.insert(id, range);
|
self.token_map.insert(id, range);
|
||||||
|
@ -805,10 +831,10 @@ impl<'a> TtTreeSink<'a> {
|
||||||
}
|
}
|
||||||
Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
|
Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
|
||||||
self.cursor = self.cursor.subtree().unwrap();
|
self.cursor = self.cursor.subtree().unwrap();
|
||||||
match subtree.delimiter {
|
match delim_to_str(subtree.delimiter.kind, false) {
|
||||||
Some(d) => {
|
Some(it) => {
|
||||||
self.open_delims.insert(d.id, self.text_pos);
|
self.open_delims.insert(subtree.delimiter.open, self.text_pos);
|
||||||
delim_to_str(d.kind, false)
|
it
|
||||||
}
|
}
|
||||||
None => continue,
|
None => continue,
|
||||||
}
|
}
|
||||||
|
@ -816,15 +842,21 @@ impl<'a> TtTreeSink<'a> {
|
||||||
None => {
|
None => {
|
||||||
let parent = self.cursor.end().unwrap();
|
let parent = self.cursor.end().unwrap();
|
||||||
self.cursor = self.cursor.bump();
|
self.cursor = self.cursor.bump();
|
||||||
match parent.delimiter {
|
match delim_to_str(parent.delimiter.kind, true) {
|
||||||
Some(d) => {
|
Some(it) => {
|
||||||
if let Some(open_delim) = self.open_delims.get(&d.id) {
|
if let Some(open_delim) =
|
||||||
|
self.open_delims.get(&parent.delimiter.open)
|
||||||
|
{
|
||||||
let open_range = TextRange::at(*open_delim, TextSize::of('('));
|
let open_range = TextRange::at(*open_delim, TextSize::of('('));
|
||||||
let close_range =
|
let close_range =
|
||||||
TextRange::at(self.text_pos, TextSize::of('('));
|
TextRange::at(self.text_pos, TextSize::of('('));
|
||||||
self.token_map.insert_delim(d.id, open_range, close_range);
|
self.token_map.insert_delim(
|
||||||
|
parent.delimiter.open,
|
||||||
|
open_range,
|
||||||
|
close_range,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
delim_to_str(d.kind, true)
|
it
|
||||||
}
|
}
|
||||||
None => continue,
|
None => continue,
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ fn check_punct_spacing(fixture: &str) {
|
||||||
let mut cursor = buf.begin();
|
let mut cursor = buf.begin();
|
||||||
while !cursor.eof() {
|
while !cursor.eof() {
|
||||||
while let Some(token_tree) = cursor.token_tree() {
|
while let Some(token_tree) = cursor.token_tree() {
|
||||||
if let TokenTreeRef::Leaf(Leaf::Punct(Punct { spacing, id, .. }), _) = token_tree {
|
if let TokenTreeRef::Leaf(Leaf::Punct(Punct { spacing, span, .. }), _) = token_tree {
|
||||||
if let Some(expected) = annotations.remove(id) {
|
if let Some(expected) = annotations.remove(span) {
|
||||||
assert_eq!(expected, *spacing);
|
assert_eq!(expected, *spacing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
//! format that works for our parser.
|
//! format that works for our parser.
|
||||||
|
|
||||||
use syntax::{SyntaxKind, SyntaxKind::*, T};
|
use syntax::{SyntaxKind, SyntaxKind::*, T};
|
||||||
use tt::buffer::TokenBuffer;
|
|
||||||
|
use crate::tt::buffer::TokenBuffer;
|
||||||
|
|
||||||
pub(crate) fn to_parser_input(buffer: &TokenBuffer<'_>) -> parser::Input {
|
pub(crate) fn to_parser_input(buffer: &TokenBuffer<'_>) -> parser::Input {
|
||||||
let mut res = parser::Input::default();
|
let mut res = parser::Input::default();
|
||||||
|
@ -70,23 +71,25 @@ pub(crate) fn to_parser_input(buffer: &TokenBuffer<'_>) -> parser::Input {
|
||||||
cursor.bump()
|
cursor.bump()
|
||||||
}
|
}
|
||||||
Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
|
Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
|
||||||
if let Some(d) = subtree.delimiter_kind() {
|
if let Some(kind) = match subtree.delimiter.kind {
|
||||||
res.push(match d {
|
tt::DelimiterKind::Parenthesis => Some(T!['(']),
|
||||||
tt::DelimiterKind::Parenthesis => T!['('],
|
tt::DelimiterKind::Brace => Some(T!['{']),
|
||||||
tt::DelimiterKind::Brace => T!['{'],
|
tt::DelimiterKind::Bracket => Some(T!['[']),
|
||||||
tt::DelimiterKind::Bracket => T!['['],
|
tt::DelimiterKind::Invisible => None,
|
||||||
});
|
} {
|
||||||
|
res.push(kind);
|
||||||
}
|
}
|
||||||
cursor.subtree().unwrap()
|
cursor.subtree().unwrap()
|
||||||
}
|
}
|
||||||
None => match cursor.end() {
|
None => match cursor.end() {
|
||||||
Some(subtree) => {
|
Some(subtree) => {
|
||||||
if let Some(d) = subtree.delimiter_kind() {
|
if let Some(kind) = match subtree.delimiter.kind {
|
||||||
res.push(match d {
|
tt::DelimiterKind::Parenthesis => Some(T![')']),
|
||||||
tt::DelimiterKind::Parenthesis => T![')'],
|
tt::DelimiterKind::Brace => Some(T!['}']),
|
||||||
tt::DelimiterKind::Brace => T!['}'],
|
tt::DelimiterKind::Bracket => Some(T![']']),
|
||||||
tt::DelimiterKind::Bracket => T![']'],
|
tt::DelimiterKind::Invisible => None,
|
||||||
})
|
} {
|
||||||
|
res.push(kind);
|
||||||
}
|
}
|
||||||
cursor.bump()
|
cursor.bump()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,8 @@
|
||||||
|
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use syntax::SyntaxKind;
|
use syntax::SyntaxKind;
|
||||||
use tt::buffer::TokenBuffer;
|
|
||||||
|
|
||||||
use crate::{to_parser_input::to_parser_input, ExpandError, ExpandResult};
|
use crate::{to_parser_input::to_parser_input, tt, ExpandError, ExpandResult};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct TtIter<'a> {
|
pub(crate) struct TtIter<'a> {
|
||||||
|
@ -135,7 +134,7 @@ impl<'a> TtIter<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
entry_point: parser::PrefixEntryPoint,
|
entry_point: parser::PrefixEntryPoint,
|
||||||
) -> ExpandResult<Option<tt::TokenTree>> {
|
) -> ExpandResult<Option<tt::TokenTree>> {
|
||||||
let buffer = TokenBuffer::from_tokens(self.inner.as_slice());
|
let buffer = tt::buffer::TokenBuffer::from_tokens(self.inner.as_slice());
|
||||||
let parser_input = to_parser_input(&buffer);
|
let parser_input = to_parser_input(&buffer);
|
||||||
let tree_traversal = entry_point.parse(&parser_input);
|
let tree_traversal = entry_point.parse(&parser_input);
|
||||||
|
|
||||||
|
@ -178,7 +177,7 @@ impl<'a> TtIter<'a> {
|
||||||
1 => Some(res[0].cloned()),
|
1 => Some(res[0].cloned()),
|
||||||
0 => None,
|
0 => None,
|
||||||
_ => Some(tt::TokenTree::Subtree(tt::Subtree {
|
_ => Some(tt::TokenTree::Subtree(tt::Subtree {
|
||||||
delimiter: None,
|
delimiter: tt::Delimiter::unspecified(),
|
||||||
token_trees: res.into_iter().map(|it| it.cloned()).collect(),
|
token_trees: res.into_iter().map(|it| it.cloned()).collect(),
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,8 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tt::Subtree;
|
|
||||||
|
use ::tt::token_id as tt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
msg::{ExpandMacro, FlatTree, PanicMessage},
|
msg::{ExpandMacro, FlatTree, PanicMessage},
|
||||||
|
@ -151,10 +152,10 @@ impl ProcMacro {
|
||||||
|
|
||||||
pub fn expand(
|
pub fn expand(
|
||||||
&self,
|
&self,
|
||||||
subtree: &Subtree,
|
subtree: &tt::Subtree,
|
||||||
attr: Option<&Subtree>,
|
attr: Option<&tt::Subtree>,
|
||||||
env: Vec<(String, String)>,
|
env: Vec<(String, String)>,
|
||||||
) -> Result<Result<Subtree, PanicMessage>, ServerError> {
|
) -> Result<Result<tt::Subtree, PanicMessage>, ServerError> {
|
||||||
let current_dir = env
|
let current_dir = env
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(name, _)| name == "CARGO_MANIFEST_DIR")
|
.find(|(name, _)| name == "CARGO_MANIFEST_DIR")
|
||||||
|
|
|
@ -107,27 +107,31 @@ fn write_json(out: &mut impl Write, msg: &str) -> io::Result<()> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use tt::*;
|
use crate::tt::*;
|
||||||
|
|
||||||
fn fixture_token_tree() -> Subtree {
|
fn fixture_token_tree() -> Subtree {
|
||||||
let mut subtree = Subtree::default();
|
let mut subtree = Subtree { delimiter: Delimiter::unspecified(), token_trees: Vec::new() };
|
||||||
subtree
|
subtree
|
||||||
.token_trees
|
.token_trees
|
||||||
.push(TokenTree::Leaf(Ident { text: "struct".into(), id: TokenId(0) }.into()));
|
.push(TokenTree::Leaf(Ident { text: "struct".into(), span: TokenId(0) }.into()));
|
||||||
subtree
|
subtree
|
||||||
.token_trees
|
.token_trees
|
||||||
.push(TokenTree::Leaf(Ident { text: "Foo".into(), id: TokenId(1) }.into()));
|
.push(TokenTree::Leaf(Ident { text: "Foo".into(), span: TokenId(1) }.into()));
|
||||||
subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
|
subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
|
||||||
text: "Foo".into(),
|
text: "Foo".into(),
|
||||||
id: TokenId::unspecified(),
|
span: TokenId::unspecified(),
|
||||||
})));
|
})));
|
||||||
subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
|
subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
|
||||||
char: '@',
|
char: '@',
|
||||||
id: TokenId::unspecified(),
|
span: TokenId::unspecified(),
|
||||||
spacing: Spacing::Joint,
|
spacing: Spacing::Joint,
|
||||||
})));
|
})));
|
||||||
subtree.token_trees.push(TokenTree::Subtree(Subtree {
|
subtree.token_trees.push(TokenTree::Subtree(Subtree {
|
||||||
delimiter: Some(Delimiter { id: TokenId(2), kind: DelimiterKind::Brace }),
|
delimiter: Delimiter {
|
||||||
|
open: TokenId(2),
|
||||||
|
close: TokenId::UNSPECIFIED,
|
||||||
|
kind: DelimiterKind::Brace,
|
||||||
|
},
|
||||||
token_trees: vec![],
|
token_trees: vec![],
|
||||||
}));
|
}));
|
||||||
subtree
|
subtree
|
||||||
|
|
|
@ -38,7 +38,8 @@
|
||||||
use std::collections::{HashMap, VecDeque};
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tt::TokenId;
|
|
||||||
|
use crate::tt::{self, TokenId};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct FlatTree {
|
pub struct FlatTree {
|
||||||
|
@ -52,7 +53,7 @@ pub struct FlatTree {
|
||||||
|
|
||||||
struct SubtreeRepr {
|
struct SubtreeRepr {
|
||||||
id: tt::TokenId,
|
id: tt::TokenId,
|
||||||
kind: Option<tt::DelimiterKind>,
|
kind: tt::DelimiterKind,
|
||||||
tt: [u32; 2],
|
tt: [u32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,19 +125,19 @@ impl FlatTree {
|
||||||
impl SubtreeRepr {
|
impl SubtreeRepr {
|
||||||
fn write(self) -> [u32; 4] {
|
fn write(self) -> [u32; 4] {
|
||||||
let kind = match self.kind {
|
let kind = match self.kind {
|
||||||
None => 0,
|
tt::DelimiterKind::Invisible => 0,
|
||||||
Some(tt::DelimiterKind::Parenthesis) => 1,
|
tt::DelimiterKind::Parenthesis => 1,
|
||||||
Some(tt::DelimiterKind::Brace) => 2,
|
tt::DelimiterKind::Brace => 2,
|
||||||
Some(tt::DelimiterKind::Bracket) => 3,
|
tt::DelimiterKind::Bracket => 3,
|
||||||
};
|
};
|
||||||
[self.id.0, kind, self.tt[0], self.tt[1]]
|
[self.id.0, kind, self.tt[0], self.tt[1]]
|
||||||
}
|
}
|
||||||
fn read([id, kind, lo, len]: [u32; 4]) -> SubtreeRepr {
|
fn read([id, kind, lo, len]: [u32; 4]) -> SubtreeRepr {
|
||||||
let kind = match kind {
|
let kind = match kind {
|
||||||
0 => None,
|
0 => tt::DelimiterKind::Invisible,
|
||||||
1 => Some(tt::DelimiterKind::Parenthesis),
|
1 => tt::DelimiterKind::Parenthesis,
|
||||||
2 => Some(tt::DelimiterKind::Brace),
|
2 => tt::DelimiterKind::Brace,
|
||||||
3 => Some(tt::DelimiterKind::Bracket),
|
3 => tt::DelimiterKind::Bracket,
|
||||||
other => panic!("bad kind {other}"),
|
other => panic!("bad kind {other}"),
|
||||||
};
|
};
|
||||||
SubtreeRepr { id: TokenId(id), kind, tt: [lo, len] }
|
SubtreeRepr { id: TokenId(id), kind, tt: [lo, len] }
|
||||||
|
@ -216,7 +217,7 @@ impl<'a> Writer<'a> {
|
||||||
tt::Leaf::Literal(lit) => {
|
tt::Leaf::Literal(lit) => {
|
||||||
let idx = self.literal.len() as u32;
|
let idx = self.literal.len() as u32;
|
||||||
let text = self.intern(&lit.text);
|
let text = self.intern(&lit.text);
|
||||||
self.literal.push(LiteralRepr { id: lit.id, text });
|
self.literal.push(LiteralRepr { id: lit.span, text });
|
||||||
idx << 2 | 0b01
|
idx << 2 | 0b01
|
||||||
}
|
}
|
||||||
tt::Leaf::Punct(punct) => {
|
tt::Leaf::Punct(punct) => {
|
||||||
|
@ -224,14 +225,14 @@ impl<'a> Writer<'a> {
|
||||||
self.punct.push(PunctRepr {
|
self.punct.push(PunctRepr {
|
||||||
char: punct.char,
|
char: punct.char,
|
||||||
spacing: punct.spacing,
|
spacing: punct.spacing,
|
||||||
id: punct.id,
|
id: punct.span,
|
||||||
});
|
});
|
||||||
idx << 2 | 0b10
|
idx << 2 | 0b10
|
||||||
}
|
}
|
||||||
tt::Leaf::Ident(ident) => {
|
tt::Leaf::Ident(ident) => {
|
||||||
let idx = self.ident.len() as u32;
|
let idx = self.ident.len() as u32;
|
||||||
let text = self.intern(&ident.text);
|
let text = self.intern(&ident.text);
|
||||||
self.ident.push(IdentRepr { id: ident.id, text });
|
self.ident.push(IdentRepr { id: ident.span, text });
|
||||||
idx << 2 | 0b11
|
idx << 2 | 0b11
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -243,8 +244,8 @@ impl<'a> Writer<'a> {
|
||||||
|
|
||||||
fn enqueue(&mut self, subtree: &'a tt::Subtree) -> u32 {
|
fn enqueue(&mut self, subtree: &'a tt::Subtree) -> u32 {
|
||||||
let idx = self.subtree.len();
|
let idx = self.subtree.len();
|
||||||
let delimiter_id = subtree.delimiter.map_or(TokenId::unspecified(), |it| it.id);
|
let delimiter_id = subtree.delimiter.open;
|
||||||
let delimiter_kind = subtree.delimiter.map(|it| it.kind);
|
let delimiter_kind = subtree.delimiter.kind;
|
||||||
self.subtree.push(SubtreeRepr { id: delimiter_id, kind: delimiter_kind, tt: [!0, !0] });
|
self.subtree.push(SubtreeRepr { id: delimiter_id, kind: delimiter_kind, tt: [!0, !0] });
|
||||||
self.work.push_back((idx, subtree));
|
self.work.push_back((idx, subtree));
|
||||||
idx as u32
|
idx as u32
|
||||||
|
@ -276,7 +277,11 @@ impl Reader {
|
||||||
let repr = &self.subtree[i];
|
let repr = &self.subtree[i];
|
||||||
let token_trees = &self.token_tree[repr.tt[0] as usize..repr.tt[1] as usize];
|
let token_trees = &self.token_tree[repr.tt[0] as usize..repr.tt[1] as usize];
|
||||||
let s = tt::Subtree {
|
let s = tt::Subtree {
|
||||||
delimiter: repr.kind.map(|kind| tt::Delimiter { id: repr.id, kind }),
|
delimiter: tt::Delimiter {
|
||||||
|
open: repr.id,
|
||||||
|
close: TokenId::UNSPECIFIED,
|
||||||
|
kind: repr.kind,
|
||||||
|
},
|
||||||
token_trees: token_trees
|
token_trees: token_trees
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
|
@ -291,7 +296,7 @@ impl Reader {
|
||||||
let repr = &self.literal[idx];
|
let repr = &self.literal[idx];
|
||||||
tt::Leaf::Literal(tt::Literal {
|
tt::Leaf::Literal(tt::Literal {
|
||||||
text: self.text[repr.text as usize].as_str().into(),
|
text: self.text[repr.text as usize].as_str().into(),
|
||||||
id: repr.id,
|
span: repr.id,
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
@ -300,7 +305,7 @@ impl Reader {
|
||||||
tt::Leaf::Punct(tt::Punct {
|
tt::Leaf::Punct(tt::Punct {
|
||||||
char: repr.char,
|
char: repr.char,
|
||||||
spacing: repr.spacing,
|
spacing: repr.spacing,
|
||||||
id: repr.id,
|
span: repr.id,
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
@ -308,7 +313,7 @@ impl Reader {
|
||||||
let repr = &self.ident[idx];
|
let repr = &self.ident[idx];
|
||||||
tt::Leaf::Ident(tt::Ident {
|
tt::Leaf::Ident(tt::Ident {
|
||||||
text: self.text[repr.text as usize].as_str().into(),
|
text: self.text[repr.text as usize].as_str().into(),
|
||||||
id: repr.id,
|
span: repr.id,
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ mod ra_server;
|
||||||
use libloading::Library;
|
use libloading::Library;
|
||||||
use proc_macro_api::ProcMacroKind;
|
use proc_macro_api::ProcMacroKind;
|
||||||
|
|
||||||
|
use super::tt;
|
||||||
use super::PanicMessage;
|
use super::PanicMessage;
|
||||||
|
|
||||||
pub use ra_server::TokenStream;
|
pub use ra_server::TokenStream;
|
||||||
|
|
|
@ -15,6 +15,8 @@ use std::hash::Hash;
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
use std::{ascii, vec::IntoIter};
|
use std::{ascii, vec::IntoIter};
|
||||||
|
|
||||||
|
use crate::tt;
|
||||||
|
|
||||||
type Group = tt::Subtree;
|
type Group = tt::Subtree;
|
||||||
type TokenTree = tt::TokenTree;
|
type TokenTree = tt::TokenTree;
|
||||||
type Punct = tt::Punct;
|
type Punct = tt::Punct;
|
||||||
|
@ -33,7 +35,7 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_subtree(subtree: tt::Subtree) -> Self {
|
pub fn with_subtree(subtree: tt::Subtree) -> Self {
|
||||||
if subtree.delimiter.is_some() {
|
if subtree.delimiter.kind != tt::DelimiterKind::Invisible {
|
||||||
TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
|
TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
|
||||||
} else {
|
} else {
|
||||||
TokenStream { token_trees: subtree.token_trees }
|
TokenStream { token_trees: subtree.token_trees }
|
||||||
|
@ -41,7 +43,7 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_subtree(self) -> tt::Subtree {
|
pub fn into_subtree(self) -> tt::Subtree {
|
||||||
tt::Subtree { delimiter: None, token_trees: self.token_trees }
|
tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: self.token_trees }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
|
@ -84,7 +86,9 @@ impl Extend<TokenStream> for TokenStream {
|
||||||
for item in streams {
|
for item in streams {
|
||||||
for tkn in item {
|
for tkn in item {
|
||||||
match tkn {
|
match tkn {
|
||||||
tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => {
|
tt::TokenTree::Subtree(subtree)
|
||||||
|
if subtree.delimiter.kind == tt::DelimiterKind::Invisible =>
|
||||||
|
{
|
||||||
self.token_trees.extend(subtree.token_trees);
|
self.token_trees.extend(subtree.token_trees);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -165,7 +169,7 @@ pub struct TokenStreamBuilder {
|
||||||
pub mod token_stream {
|
pub mod token_stream {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use super::{TokenStream, TokenTree};
|
use super::{tt, TokenStream, TokenTree};
|
||||||
|
|
||||||
/// An iterator over `TokenStream`'s `TokenTree`s.
|
/// An iterator over `TokenStream`'s `TokenTree`s.
|
||||||
/// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups,
|
/// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups,
|
||||||
|
@ -202,15 +206,17 @@ pub mod token_stream {
|
||||||
|
|
||||||
impl ToString for TokenStream {
|
impl ToString for TokenStream {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
tt::pretty(&self.token_trees)
|
::tt::pretty(&self.token_trees)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree {
|
fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree {
|
||||||
tt::Subtree {
|
tt::Subtree {
|
||||||
delimiter: subtree
|
delimiter: tt::Delimiter {
|
||||||
.delimiter
|
open: tt::TokenId::UNSPECIFIED,
|
||||||
.map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }),
|
close: tt::TokenId::UNSPECIFIED,
|
||||||
|
..subtree.delimiter
|
||||||
|
},
|
||||||
token_trees: subtree
|
token_trees: subtree
|
||||||
.token_trees
|
.token_trees
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -233,13 +239,13 @@ pub mod token_stream {
|
||||||
fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf {
|
fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf {
|
||||||
match leaf {
|
match leaf {
|
||||||
tt::Leaf::Literal(lit) => {
|
tt::Leaf::Literal(lit) => {
|
||||||
tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit })
|
tt::Leaf::Literal(tt::Literal { span: tt::TokenId::unspecified(), ..lit })
|
||||||
}
|
}
|
||||||
tt::Leaf::Punct(punct) => {
|
tt::Leaf::Punct(punct) => {
|
||||||
tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct })
|
tt::Leaf::Punct(tt::Punct { span: tt::TokenId::unspecified(), ..punct })
|
||||||
}
|
}
|
||||||
tt::Leaf::Ident(ident) => {
|
tt::Leaf::Ident(ident) => {
|
||||||
tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident })
|
tt::Leaf::Ident(tt::Ident { span: tt::TokenId::unspecified(), ..ident })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,22 +395,22 @@ impl server::TokenStream for RustAnalyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delim_to_internal(d: bridge::Delimiter) -> Option<tt::Delimiter> {
|
fn delim_to_internal(d: bridge::Delimiter) -> tt::Delimiter {
|
||||||
let kind = match d {
|
let kind = match d {
|
||||||
bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis,
|
bridge::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis,
|
||||||
bridge::Delimiter::Brace => tt::DelimiterKind::Brace,
|
bridge::Delimiter::Brace => tt::DelimiterKind::Brace,
|
||||||
bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket,
|
bridge::Delimiter::Bracket => tt::DelimiterKind::Bracket,
|
||||||
bridge::Delimiter::None => return None,
|
bridge::Delimiter::None => tt::DelimiterKind::Invisible,
|
||||||
};
|
};
|
||||||
Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind })
|
tt::Delimiter { open: tt::TokenId::unspecified(), close: tt::TokenId::unspecified(), kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delim_to_external(d: Option<tt::Delimiter>) -> bridge::Delimiter {
|
fn delim_to_external(d: tt::Delimiter) -> bridge::Delimiter {
|
||||||
match d.map(|it| it.kind) {
|
match d.kind {
|
||||||
Some(tt::DelimiterKind::Parenthesis) => bridge::Delimiter::Parenthesis,
|
tt::DelimiterKind::Parenthesis => bridge::Delimiter::Parenthesis,
|
||||||
Some(tt::DelimiterKind::Brace) => bridge::Delimiter::Brace,
|
tt::DelimiterKind::Brace => bridge::Delimiter::Brace,
|
||||||
Some(tt::DelimiterKind::Bracket) => bridge::Delimiter::Bracket,
|
tt::DelimiterKind::Bracket => bridge::Delimiter::Bracket,
|
||||||
None => bridge::Delimiter::None,
|
tt::DelimiterKind::Invisible => bridge::Delimiter::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,23 +449,19 @@ impl server::Group for RustAnalyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span(&mut self, group: &Self::Group) -> Self::Span {
|
fn span(&mut self, group: &Self::Group) -> Self::Span {
|
||||||
group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
|
group.delimiter.open
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
|
fn set_span(&mut self, group: &mut Self::Group, span: Self::Span) {
|
||||||
if let Some(delim) = &mut group.delimiter {
|
group.delimiter.open = span;
|
||||||
delim.id = span;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span_open(&mut self, group: &Self::Group) -> Self::Span {
|
fn span_open(&mut self, group: &Self::Group) -> Self::Span {
|
||||||
// FIXME we only store one `TokenId` for the delimiters
|
group.delimiter.open
|
||||||
group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span_close(&mut self, group: &Self::Group) -> Self::Span {
|
fn span_close(&mut self, group: &Self::Group) -> Self::Span {
|
||||||
// FIXME we only store one `TokenId` for the delimiters
|
group.delimiter.close
|
||||||
group.delimiter.map(|it| it.id).unwrap_or_else(tt::TokenId::unspecified)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,7 +470,7 @@ impl server::Punct for RustAnalyzer {
|
||||||
tt::Punct {
|
tt::Punct {
|
||||||
char: ch,
|
char: ch,
|
||||||
spacing: spacing_to_internal(spacing),
|
spacing: spacing_to_internal(spacing),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn as_char(&mut self, punct: Self::Punct) -> char {
|
fn as_char(&mut self, punct: Self::Punct) -> char {
|
||||||
|
@ -478,28 +480,27 @@ impl server::Punct for RustAnalyzer {
|
||||||
spacing_to_external(punct.spacing)
|
spacing_to_external(punct.spacing)
|
||||||
}
|
}
|
||||||
fn span(&mut self, punct: Self::Punct) -> Self::Span {
|
fn span(&mut self, punct: Self::Punct) -> Self::Span {
|
||||||
punct.id
|
punct.span
|
||||||
}
|
}
|
||||||
fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
|
fn with_span(&mut self, punct: Self::Punct, span: Self::Span) -> Self::Punct {
|
||||||
tt::Punct { id: span, ..punct }
|
tt::Punct { span: span, ..punct }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl server::Ident for RustAnalyzer {
|
impl server::Ident for RustAnalyzer {
|
||||||
fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
|
fn new(&mut self, string: &str, span: Self::Span, is_raw: bool) -> Self::Ident {
|
||||||
IdentId(self.ident_interner.intern(&IdentData(tt::Ident::new_with_is_raw(
|
IdentId(self.ident_interner.intern(&IdentData(tt::Ident {
|
||||||
string.into(),
|
text: if is_raw { ::tt::SmolStr::from_iter(["r#", string]) } else { string.into() },
|
||||||
span,
|
span,
|
||||||
is_raw,
|
})))
|
||||||
))))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span(&mut self, ident: Self::Ident) -> Self::Span {
|
fn span(&mut self, ident: Self::Ident) -> Self::Span {
|
||||||
self.ident_interner.get(ident.0).0.id
|
self.ident_interner.get(ident.0).0.span
|
||||||
}
|
}
|
||||||
fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
|
fn with_span(&mut self, ident: Self::Ident, span: Self::Span) -> Self::Ident {
|
||||||
let data = self.ident_interner.get(ident.0);
|
let data = self.ident_interner.get(ident.0);
|
||||||
let new = IdentData(tt::Ident { id: span, ..data.0.clone() });
|
let new = IdentData(tt::Ident { span: span, ..data.0.clone() });
|
||||||
IdentId(self.ident_interner.intern(&new))
|
IdentId(self.ident_interner.intern(&new))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -511,7 +512,7 @@ impl server::Literal for RustAnalyzer {
|
||||||
"".to_owned()
|
"".to_owned()
|
||||||
}
|
}
|
||||||
fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
|
fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
|
||||||
Ok(Literal { text: s.into(), id: tt::TokenId::unspecified() })
|
Ok(Literal { text: s.into(), span: tt::TokenId::unspecified() })
|
||||||
}
|
}
|
||||||
fn symbol(&mut self, literal: &Self::Literal) -> String {
|
fn symbol(&mut self, literal: &Self::Literal) -> String {
|
||||||
literal.text.to_string()
|
literal.text.to_string()
|
||||||
|
@ -529,7 +530,7 @@ impl server::Literal for RustAnalyzer {
|
||||||
Ok(n) => n.to_string(),
|
Ok(n) => n.to_string(),
|
||||||
Err(_) => n.parse::<u128>().unwrap().to_string(),
|
Err(_) => n.parse::<u128>().unwrap().to_string(),
|
||||||
};
|
};
|
||||||
Literal { text: n.into(), id: tt::TokenId::unspecified() }
|
Literal { text: n.into(), span: tt::TokenId::unspecified() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
|
fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
|
||||||
|
@ -549,7 +550,7 @@ impl server::Literal for RustAnalyzer {
|
||||||
|
|
||||||
let text = def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize};
|
let text = def_suffixed_integer! {kind, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize};
|
||||||
|
|
||||||
Literal { text: text.into(), id: tt::TokenId::unspecified() }
|
Literal { text: text.into(), span: tt::TokenId::unspecified() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn float(&mut self, n: &str) -> Self::Literal {
|
fn float(&mut self, n: &str) -> Self::Literal {
|
||||||
|
@ -558,19 +559,19 @@ impl server::Literal for RustAnalyzer {
|
||||||
if !text.contains('.') {
|
if !text.contains('.') {
|
||||||
text += ".0"
|
text += ".0"
|
||||||
}
|
}
|
||||||
Literal { text: text.into(), id: tt::TokenId::unspecified() }
|
Literal { text: text.into(), span: tt::TokenId::unspecified() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f32(&mut self, n: &str) -> Self::Literal {
|
fn f32(&mut self, n: &str) -> Self::Literal {
|
||||||
let n: f32 = n.parse().unwrap();
|
let n: f32 = n.parse().unwrap();
|
||||||
let text = format!("{n}f32");
|
let text = format!("{n}f32");
|
||||||
Literal { text: text.into(), id: tt::TokenId::unspecified() }
|
Literal { text: text.into(), span: tt::TokenId::unspecified() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f64(&mut self, n: &str) -> Self::Literal {
|
fn f64(&mut self, n: &str) -> Self::Literal {
|
||||||
let n: f64 = n.parse().unwrap();
|
let n: f64 = n.parse().unwrap();
|
||||||
let text = format!("{n}f64");
|
let text = format!("{n}f64");
|
||||||
Literal { text: text.into(), id: tt::TokenId::unspecified() }
|
Literal { text: text.into(), span: tt::TokenId::unspecified() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string(&mut self, string: &str) -> Self::Literal {
|
fn string(&mut self, string: &str) -> Self::Literal {
|
||||||
|
@ -578,11 +579,11 @@ impl server::Literal for RustAnalyzer {
|
||||||
for ch in string.chars() {
|
for ch in string.chars() {
|
||||||
escaped.extend(ch.escape_debug());
|
escaped.extend(ch.escape_debug());
|
||||||
}
|
}
|
||||||
Literal { text: format!("\"{escaped}\"").into(), id: tt::TokenId::unspecified() }
|
Literal { text: format!("\"{escaped}\"").into(), span: tt::TokenId::unspecified() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn character(&mut self, ch: char) -> Self::Literal {
|
fn character(&mut self, ch: char) -> Self::Literal {
|
||||||
Literal { text: format!("'{ch}'").into(), id: tt::TokenId::unspecified() }
|
Literal { text: format!("'{ch}'").into(), span: tt::TokenId::unspecified() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
|
fn byte_string(&mut self, bytes: &[u8]) -> Self::Literal {
|
||||||
|
@ -593,15 +594,15 @@ impl server::Literal for RustAnalyzer {
|
||||||
.map(Into::<char>::into)
|
.map(Into::<char>::into)
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
Literal { text: format!("b\"{string}\"").into(), id: tt::TokenId::unspecified() }
|
Literal { text: format!("b\"{string}\"").into(), span: tt::TokenId::unspecified() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn span(&mut self, literal: &Self::Literal) -> Self::Span {
|
fn span(&mut self, literal: &Self::Literal) -> Self::Span {
|
||||||
literal.id
|
literal.span
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
|
fn set_span(&mut self, literal: &mut Self::Literal, span: Self::Span) {
|
||||||
literal.id = span;
|
literal.span = span;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subspan(
|
fn subspan(
|
||||||
|
@ -784,17 +785,18 @@ mod tests {
|
||||||
token_trees: vec![
|
token_trees: vec![
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: "struct".into(),
|
text: "struct".into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
})),
|
})),
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: "T".into(),
|
text: "T".into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
})),
|
})),
|
||||||
tt::TokenTree::Subtree(tt::Subtree {
|
tt::TokenTree::Subtree(tt::Subtree {
|
||||||
delimiter: Some(tt::Delimiter {
|
delimiter: tt::Delimiter {
|
||||||
id: tt::TokenId::unspecified(),
|
open: tt::TokenId::unspecified(),
|
||||||
|
close: tt::TokenId::unspecified(),
|
||||||
kind: tt::DelimiterKind::Brace,
|
kind: tt::DelimiterKind::Brace,
|
||||||
}),
|
},
|
||||||
token_trees: vec![],
|
token_trees: vec![],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
@ -807,13 +809,14 @@ mod tests {
|
||||||
fn test_ra_server_from_str() {
|
fn test_ra_server_from_str() {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
|
let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
|
||||||
delimiter: Some(tt::Delimiter {
|
delimiter: tt::Delimiter {
|
||||||
id: tt::TokenId::unspecified(),
|
open: tt::TokenId::unspecified(),
|
||||||
|
close: tt::TokenId::unspecified(),
|
||||||
kind: tt::DelimiterKind::Parenthesis,
|
kind: tt::DelimiterKind::Parenthesis,
|
||||||
}),
|
},
|
||||||
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: "a".into(),
|
text: "a".into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}))],
|
}))],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -830,7 +833,7 @@ mod tests {
|
||||||
underscore.token_trees[0],
|
underscore.token_trees[0],
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: "_".into(),
|
text: "_".into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ mod ra_server;
|
||||||
use libloading::Library;
|
use libloading::Library;
|
||||||
use proc_macro_api::ProcMacroKind;
|
use proc_macro_api::ProcMacroKind;
|
||||||
|
|
||||||
use super::PanicMessage;
|
use super::{tt, PanicMessage};
|
||||||
|
|
||||||
pub use ra_server::TokenStream;
|
pub use ra_server::TokenStream;
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ pub use symbol::*;
|
||||||
|
|
||||||
use std::ops::Bound;
|
use std::ops::Bound;
|
||||||
|
|
||||||
|
use crate::tt;
|
||||||
|
|
||||||
type Group = tt::Subtree;
|
type Group = tt::Subtree;
|
||||||
type TokenTree = tt::TokenTree;
|
type TokenTree = tt::TokenTree;
|
||||||
type Punct = tt::Punct;
|
type Punct = tt::Punct;
|
||||||
|
@ -108,8 +110,9 @@ impl server::TokenStream for RustAnalyzer {
|
||||||
|
|
||||||
bridge::TokenTree::Ident(ident) => {
|
bridge::TokenTree::Ident(ident) => {
|
||||||
let text = ident.sym.text();
|
let text = ident.sym.text();
|
||||||
let text = if ident.is_raw { tt::SmolStr::from_iter(["r#", &text]) } else { text };
|
let text =
|
||||||
let ident: tt::Ident = tt::Ident { text, id: ident.span };
|
if ident.is_raw { ::tt::SmolStr::from_iter(["r#", &text]) } else { text };
|
||||||
|
let ident: tt::Ident = tt::Ident { text, span: ident.span };
|
||||||
let leaf = tt::Leaf::from(ident);
|
let leaf = tt::Leaf::from(ident);
|
||||||
let tree = TokenTree::from(leaf);
|
let tree = TokenTree::from(leaf);
|
||||||
Self::TokenStream::from_iter(vec![tree])
|
Self::TokenStream::from_iter(vec![tree])
|
||||||
|
@ -118,9 +121,9 @@ impl server::TokenStream for RustAnalyzer {
|
||||||
bridge::TokenTree::Literal(literal) => {
|
bridge::TokenTree::Literal(literal) => {
|
||||||
let literal = LiteralFormatter(literal);
|
let literal = LiteralFormatter(literal);
|
||||||
let text = literal
|
let text = literal
|
||||||
.with_stringify_parts(|parts| tt::SmolStr::from_iter(parts.iter().copied()));
|
.with_stringify_parts(|parts| ::tt::SmolStr::from_iter(parts.iter().copied()));
|
||||||
|
|
||||||
let literal = tt::Literal { text, id: literal.0.span };
|
let literal = tt::Literal { text, span: literal.0.span };
|
||||||
let leaf = tt::Leaf::from(literal);
|
let leaf = tt::Leaf::from(literal);
|
||||||
let tree = TokenTree::from(leaf);
|
let tree = TokenTree::from(leaf);
|
||||||
Self::TokenStream::from_iter(vec![tree])
|
Self::TokenStream::from_iter(vec![tree])
|
||||||
|
@ -130,7 +133,7 @@ impl server::TokenStream for RustAnalyzer {
|
||||||
let punct = tt::Punct {
|
let punct = tt::Punct {
|
||||||
char: p.ch as char,
|
char: p.ch as char,
|
||||||
spacing: if p.joint { Spacing::Joint } else { Spacing::Alone },
|
spacing: if p.joint { Spacing::Joint } else { Spacing::Alone },
|
||||||
id: p.span,
|
span: p.span,
|
||||||
};
|
};
|
||||||
let leaf = tt::Leaf::from(punct);
|
let leaf = tt::Leaf::from(punct);
|
||||||
let tree = TokenTree::from(leaf);
|
let tree = TokenTree::from(leaf);
|
||||||
|
@ -184,7 +187,7 @@ impl server::TokenStream for RustAnalyzer {
|
||||||
bridge::TokenTree::Ident(bridge::Ident {
|
bridge::TokenTree::Ident(bridge::Ident {
|
||||||
sym: Symbol::intern(ident.text.trim_start_matches("r#")),
|
sym: Symbol::intern(ident.text.trim_start_matches("r#")),
|
||||||
is_raw: ident.text.starts_with("r#"),
|
is_raw: ident.text.starts_with("r#"),
|
||||||
span: ident.id,
|
span: ident.span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
|
tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
|
||||||
|
@ -194,14 +197,14 @@ impl server::TokenStream for RustAnalyzer {
|
||||||
symbol: Symbol::intern(&lit.text),
|
symbol: Symbol::intern(&lit.text),
|
||||||
// FIXME: handle suffixes
|
// FIXME: handle suffixes
|
||||||
suffix: None,
|
suffix: None,
|
||||||
span: lit.id,
|
span: lit.span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => {
|
tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) => {
|
||||||
bridge::TokenTree::Punct(bridge::Punct {
|
bridge::TokenTree::Punct(bridge::Punct {
|
||||||
ch: punct.char as u8,
|
ch: punct.char as u8,
|
||||||
joint: punct.spacing == Spacing::Joint,
|
joint: punct.spacing == Spacing::Joint,
|
||||||
span: punct.id,
|
span: punct.span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(bridge::Group {
|
tt::TokenTree::Subtree(subtree) => bridge::TokenTree::Group(bridge::Group {
|
||||||
|
@ -211,31 +214,29 @@ impl server::TokenStream for RustAnalyzer {
|
||||||
} else {
|
} else {
|
||||||
Some(subtree.token_trees.into_iter().collect())
|
Some(subtree.token_trees.into_iter().collect())
|
||||||
},
|
},
|
||||||
span: bridge::DelimSpan::from_single(
|
span: bridge::DelimSpan::from_single(subtree.delimiter.open),
|
||||||
subtree.delimiter.map_or(Span::unspecified(), |del| del.id),
|
|
||||||
),
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delim_to_internal(d: proc_macro::Delimiter) -> Option<tt::Delimiter> {
|
fn delim_to_internal(d: proc_macro::Delimiter) -> tt::Delimiter {
|
||||||
let kind = match d {
|
let kind = match d {
|
||||||
proc_macro::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis,
|
proc_macro::Delimiter::Parenthesis => tt::DelimiterKind::Parenthesis,
|
||||||
proc_macro::Delimiter::Brace => tt::DelimiterKind::Brace,
|
proc_macro::Delimiter::Brace => tt::DelimiterKind::Brace,
|
||||||
proc_macro::Delimiter::Bracket => tt::DelimiterKind::Bracket,
|
proc_macro::Delimiter::Bracket => tt::DelimiterKind::Bracket,
|
||||||
proc_macro::Delimiter::None => return None,
|
proc_macro::Delimiter::None => tt::DelimiterKind::Invisible,
|
||||||
};
|
};
|
||||||
Some(tt::Delimiter { id: tt::TokenId::unspecified(), kind })
|
tt::Delimiter { open: tt::TokenId::unspecified(), close: tt::TokenId::unspecified(), kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delim_to_external(d: Option<tt::Delimiter>) -> proc_macro::Delimiter {
|
fn delim_to_external(d: tt::Delimiter) -> proc_macro::Delimiter {
|
||||||
match d.map(|it| it.kind) {
|
match d.kind {
|
||||||
Some(tt::DelimiterKind::Parenthesis) => proc_macro::Delimiter::Parenthesis,
|
tt::DelimiterKind::Parenthesis => proc_macro::Delimiter::Parenthesis,
|
||||||
Some(tt::DelimiterKind::Brace) => proc_macro::Delimiter::Brace,
|
tt::DelimiterKind::Brace => proc_macro::Delimiter::Brace,
|
||||||
Some(tt::DelimiterKind::Bracket) => proc_macro::Delimiter::Bracket,
|
tt::DelimiterKind::Bracket => proc_macro::Delimiter::Bracket,
|
||||||
None => proc_macro::Delimiter::None,
|
tt::DelimiterKind::Invisible => proc_macro::Delimiter::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +350,7 @@ impl server::Server for RustAnalyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn intern_symbol(ident: &str) -> Self::Symbol {
|
fn intern_symbol(ident: &str) -> Self::Symbol {
|
||||||
Symbol::intern(&tt::SmolStr::from(ident))
|
Symbol::intern(&::tt::SmolStr::from(ident))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
fn with_symbol_string(symbol: &Self::Symbol, f: impl FnOnce(&str)) {
|
||||||
|
@ -413,17 +414,18 @@ mod tests {
|
||||||
token_trees: vec![
|
token_trees: vec![
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: "struct".into(),
|
text: "struct".into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
})),
|
})),
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: "T".into(),
|
text: "T".into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
})),
|
})),
|
||||||
tt::TokenTree::Subtree(tt::Subtree {
|
tt::TokenTree::Subtree(tt::Subtree {
|
||||||
delimiter: Some(tt::Delimiter {
|
delimiter: tt::Delimiter {
|
||||||
id: tt::TokenId::unspecified(),
|
open: tt::TokenId::unspecified(),
|
||||||
|
close: tt::TokenId::unspecified(),
|
||||||
kind: tt::DelimiterKind::Brace,
|
kind: tt::DelimiterKind::Brace,
|
||||||
}),
|
},
|
||||||
token_trees: vec![],
|
token_trees: vec![],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
@ -436,13 +438,14 @@ mod tests {
|
||||||
fn test_ra_server_from_str() {
|
fn test_ra_server_from_str() {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
|
let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree {
|
||||||
delimiter: Some(tt::Delimiter {
|
delimiter: tt::Delimiter {
|
||||||
id: tt::TokenId::unspecified(),
|
open: tt::TokenId::unspecified(),
|
||||||
|
close: tt::TokenId::unspecified(),
|
||||||
kind: tt::DelimiterKind::Parenthesis,
|
kind: tt::DelimiterKind::Parenthesis,
|
||||||
}),
|
},
|
||||||
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: "a".into(),
|
text: "a".into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}))],
|
}))],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -459,7 +462,7 @@ mod tests {
|
||||||
underscore.token_trees[0],
|
underscore.token_trees[0],
|
||||||
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
|
||||||
text: "_".into(),
|
text: "_".into(),
|
||||||
id: tt::TokenId::unspecified(),
|
span: tt::TokenId::unspecified(),
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! TokenStream implementation used by sysroot ABI
|
//! TokenStream implementation used by sysroot ABI
|
||||||
|
|
||||||
use tt::TokenTree;
|
use crate::tt::{self, TokenTree};
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct TokenStream {
|
pub struct TokenStream {
|
||||||
|
@ -13,7 +13,7 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_subtree(subtree: tt::Subtree) -> Self {
|
pub fn with_subtree(subtree: tt::Subtree) -> Self {
|
||||||
if subtree.delimiter.is_some() {
|
if subtree.delimiter.kind != tt::DelimiterKind::Invisible {
|
||||||
TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
|
TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
|
||||||
} else {
|
} else {
|
||||||
TokenStream { token_trees: subtree.token_trees }
|
TokenStream { token_trees: subtree.token_trees }
|
||||||
|
@ -21,7 +21,7 @@ impl TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_subtree(self) -> tt::Subtree {
|
pub fn into_subtree(self) -> tt::Subtree {
|
||||||
tt::Subtree { delimiter: None, token_trees: self.token_trees }
|
tt::Subtree { delimiter: tt::Delimiter::UNSPECIFIED, token_trees: self.token_trees }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
|
@ -64,7 +64,9 @@ impl Extend<TokenStream> for TokenStream {
|
||||||
for item in streams {
|
for item in streams {
|
||||||
for tkn in item {
|
for tkn in item {
|
||||||
match tkn {
|
match tkn {
|
||||||
tt::TokenTree::Subtree(subtree) if subtree.delimiter.is_none() => {
|
tt::TokenTree::Subtree(subtree)
|
||||||
|
if subtree.delimiter.kind != tt::DelimiterKind::Invisible =>
|
||||||
|
{
|
||||||
self.token_trees.extend(subtree.token_trees);
|
self.token_trees.extend(subtree.token_trees);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -84,7 +86,7 @@ pub struct TokenStreamBuilder {
|
||||||
pub mod token_stream {
|
pub mod token_stream {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use super::{TokenStream, TokenTree};
|
use super::{tt, TokenStream, TokenTree};
|
||||||
|
|
||||||
/// An iterator over `TokenStream`'s `TokenTree`s.
|
/// An iterator over `TokenStream`'s `TokenTree`s.
|
||||||
/// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups,
|
/// The iteration is "shallow", e.g., the iterator doesn't recurse into delimited groups,
|
||||||
|
@ -121,15 +123,17 @@ pub mod token_stream {
|
||||||
|
|
||||||
impl ToString for TokenStream {
|
impl ToString for TokenStream {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
tt::pretty(&self.token_trees)
|
::tt::pretty(&self.token_trees)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree {
|
fn subtree_replace_token_ids_with_unspecified(subtree: tt::Subtree) -> tt::Subtree {
|
||||||
tt::Subtree {
|
tt::Subtree {
|
||||||
delimiter: subtree
|
delimiter: tt::Delimiter {
|
||||||
.delimiter
|
open: tt::TokenId::UNSPECIFIED,
|
||||||
.map(|d| tt::Delimiter { id: tt::TokenId::unspecified(), ..d }),
|
close: tt::TokenId::UNSPECIFIED,
|
||||||
|
..subtree.delimiter
|
||||||
|
},
|
||||||
token_trees: subtree
|
token_trees: subtree
|
||||||
.token_trees
|
.token_trees
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -152,13 +156,13 @@ pub mod token_stream {
|
||||||
fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf {
|
fn leaf_replace_token_ids_with_unspecified(leaf: tt::Leaf) -> tt::Leaf {
|
||||||
match leaf {
|
match leaf {
|
||||||
tt::Leaf::Literal(lit) => {
|
tt::Leaf::Literal(lit) => {
|
||||||
tt::Leaf::Literal(tt::Literal { id: tt::TokenId::unspecified(), ..lit })
|
tt::Leaf::Literal(tt::Literal { span: tt::TokenId::unspecified(), ..lit })
|
||||||
}
|
}
|
||||||
tt::Leaf::Punct(punct) => {
|
tt::Leaf::Punct(punct) => {
|
||||||
tt::Leaf::Punct(tt::Punct { id: tt::TokenId::unspecified(), ..punct })
|
tt::Leaf::Punct(tt::Punct { span: tt::TokenId::unspecified(), ..punct })
|
||||||
}
|
}
|
||||||
tt::Leaf::Ident(ident) => {
|
tt::Leaf::Ident(ident) => {
|
||||||
tt::Leaf::Ident(tt::Ident { id: tt::TokenId::unspecified(), ..ident })
|
tt::Leaf::Ident(tt::Ident { span: tt::TokenId::unspecified(), ..ident })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ pub(crate) use abi_sysroot::Abi as Abi_Sysroot;
|
||||||
use libloading::Library;
|
use libloading::Library;
|
||||||
use proc_macro_api::{ProcMacroKind, RustCInfo};
|
use proc_macro_api::{ProcMacroKind, RustCInfo};
|
||||||
|
|
||||||
|
use crate::tt;
|
||||||
|
|
||||||
pub struct PanicMessage {
|
pub struct PanicMessage {
|
||||||
message: Option<String>,
|
message: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ use object::Object;
|
||||||
use paths::AbsPath;
|
use paths::AbsPath;
|
||||||
use proc_macro_api::{read_dylib_info, ProcMacroKind};
|
use proc_macro_api::{read_dylib_info, ProcMacroKind};
|
||||||
|
|
||||||
|
use crate::tt;
|
||||||
|
|
||||||
use super::abis::Abi;
|
use super::abis::Abi;
|
||||||
|
|
||||||
const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";
|
const NEW_REGISTRAR_SYMBOL: &str = "_rustc_proc_macro_decls_";
|
||||||
|
|
|
@ -37,6 +37,8 @@ use proc_macro_api::{
|
||||||
ProcMacroKind,
|
ProcMacroKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use ::tt::token_id as tt;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct ProcMacroSrv {
|
pub(crate) struct ProcMacroSrv {
|
||||||
expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>,
|
expanders: HashMap<(PathBuf, SystemTime), dylib::Expander>,
|
||||||
|
|
|
@ -8,7 +8,7 @@ use expect_test::expect;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_derive_empty() {
|
fn test_derive_empty() {
|
||||||
assert_expand("DeriveEmpty", r#"struct S;"#, expect![[r#"SUBTREE $"#]]);
|
assert_expand("DeriveEmpty", r#"struct S;"#, expect!["SUBTREE $$ 4294967295 4294967295"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -17,10 +17,10 @@ fn test_derive_error() {
|
||||||
"DeriveError",
|
"DeriveError",
|
||||||
r#"struct S;"#,
|
r#"struct S;"#,
|
||||||
expect![[r##"
|
expect![[r##"
|
||||||
SUBTREE $
|
SUBTREE $$ 4294967295 4294967295
|
||||||
IDENT compile_error 4294967295
|
IDENT compile_error 4294967295
|
||||||
PUNCH ! [alone] 4294967295
|
PUNCH ! [alone] 4294967295
|
||||||
SUBTREE () 4294967295
|
SUBTREE () 4294967295 4294967295
|
||||||
LITERAL "#[derive(DeriveError)] struct S ;" 4294967295
|
LITERAL "#[derive(DeriveError)] struct S ;" 4294967295
|
||||||
PUNCH ; [alone] 4294967295"##]],
|
PUNCH ; [alone] 4294967295"##]],
|
||||||
);
|
);
|
||||||
|
@ -32,14 +32,14 @@ fn test_fn_like_macro_noop() {
|
||||||
"fn_like_noop",
|
"fn_like_noop",
|
||||||
r#"ident, 0, 1, []"#,
|
r#"ident, 0, 1, []"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
SUBTREE $
|
SUBTREE $$ 4294967295 4294967295
|
||||||
IDENT ident 4294967295
|
IDENT ident 4294967295
|
||||||
PUNCH , [alone] 4294967295
|
PUNCH , [alone] 4294967295
|
||||||
LITERAL 0 4294967295
|
LITERAL 0 4294967295
|
||||||
PUNCH , [alone] 4294967295
|
PUNCH , [alone] 4294967295
|
||||||
LITERAL 1 4294967295
|
LITERAL 1 4294967295
|
||||||
PUNCH , [alone] 4294967295
|
PUNCH , [alone] 4294967295
|
||||||
SUBTREE [] 4294967295"#]],
|
SUBTREE [] 4294967295 4294967295"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,10 +49,10 @@ fn test_fn_like_macro_clone_ident_subtree() {
|
||||||
"fn_like_clone_tokens",
|
"fn_like_clone_tokens",
|
||||||
r#"ident, []"#,
|
r#"ident, []"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
SUBTREE $
|
SUBTREE $$ 4294967295 4294967295
|
||||||
IDENT ident 4294967295
|
IDENT ident 4294967295
|
||||||
PUNCH , [alone] 4294967295
|
PUNCH , [alone] 4294967295
|
||||||
SUBTREE [] 4294967295"#]],
|
SUBTREE [] 4294967295 4294967295"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ fn test_fn_like_macro_clone_raw_ident() {
|
||||||
"fn_like_clone_tokens",
|
"fn_like_clone_tokens",
|
||||||
"r#async",
|
"r#async",
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
SUBTREE $
|
SUBTREE $$ 4294967295 4294967295
|
||||||
IDENT r#async 4294967295"#]],
|
IDENT r#async 4294967295"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ fn test_fn_like_mk_literals() {
|
||||||
"fn_like_mk_literals",
|
"fn_like_mk_literals",
|
||||||
r#""#,
|
r#""#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
SUBTREE $
|
SUBTREE $$ 4294967295 4294967295
|
||||||
LITERAL b"byte_string" 4294967295
|
LITERAL b"byte_string" 4294967295
|
||||||
LITERAL 'c' 4294967295
|
LITERAL 'c' 4294967295
|
||||||
LITERAL "string" 4294967295
|
LITERAL "string" 4294967295
|
||||||
|
@ -90,7 +90,7 @@ fn test_fn_like_mk_idents() {
|
||||||
"fn_like_mk_idents",
|
"fn_like_mk_idents",
|
||||||
r#""#,
|
r#""#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
SUBTREE $
|
SUBTREE $$ 4294967295 4294967295
|
||||||
IDENT standard 4294967295
|
IDENT standard 4294967295
|
||||||
IDENT r#raw 4294967295"#]],
|
IDENT r#raw 4294967295"#]],
|
||||||
);
|
);
|
||||||
|
@ -102,7 +102,7 @@ fn test_fn_like_macro_clone_literals() {
|
||||||
"fn_like_clone_tokens",
|
"fn_like_clone_tokens",
|
||||||
r#"1u16, 2_u32, -4i64, 3.14f32, "hello bridge""#,
|
r#"1u16, 2_u32, -4i64, 3.14f32, "hello bridge""#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
SUBTREE $
|
SUBTREE $$ 4294967295 4294967295
|
||||||
LITERAL 1u16 4294967295
|
LITERAL 1u16 4294967295
|
||||||
PUNCH , [alone] 4294967295
|
PUNCH , [alone] 4294967295
|
||||||
LITERAL 2_u32 4294967295
|
LITERAL 2_u32 4294967295
|
||||||
|
@ -126,10 +126,10 @@ fn test_attr_macro() {
|
||||||
r#"mod m {}"#,
|
r#"mod m {}"#,
|
||||||
r#"some arguments"#,
|
r#"some arguments"#,
|
||||||
expect![[r##"
|
expect![[r##"
|
||||||
SUBTREE $
|
SUBTREE $$ 4294967295 4294967295
|
||||||
IDENT compile_error 4294967295
|
IDENT compile_error 4294967295
|
||||||
PUNCH ! [alone] 4294967295
|
PUNCH ! [alone] 4294967295
|
||||||
SUBTREE () 4294967295
|
SUBTREE () 4294967295 4294967295
|
||||||
LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295
|
LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295
|
||||||
PUNCH ; [alone] 4294967295"##]],
|
PUNCH ; [alone] 4294967295"##]],
|
||||||
);
|
);
|
||||||
|
|
|
@ -34,6 +34,8 @@ use crate::{
|
||||||
op_queue::Cause,
|
op_queue::Cause,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use ::tt::token_id as tt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum ProjectWorkspaceProgress {
|
pub(crate) enum ProjectWorkspaceProgress {
|
||||||
Begin,
|
Begin,
|
||||||
|
@ -656,7 +658,7 @@ pub(crate) fn load_proc_macro(
|
||||||
_: Option<&tt::Subtree>,
|
_: Option<&tt::Subtree>,
|
||||||
_: &Env,
|
_: &Env,
|
||||||
) -> Result<tt::Subtree, ProcMacroExpansionError> {
|
) -> Result<tt::Subtree, ProcMacroExpansionError> {
|
||||||
Ok(tt::Subtree::default())
|
Ok(tt::Subtree::empty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,5 +43,14 @@ macro_rules! impl_from {
|
||||||
}
|
}
|
||||||
)*)?
|
)*)?
|
||||||
)*
|
)*
|
||||||
|
};
|
||||||
|
($($variant:ident$(<$V:ident>)?),* for $enum:ident) => {
|
||||||
|
$(
|
||||||
|
impl$(<$V>)? From<$variant$(<$V>)?> for $enum$(<$V>)? {
|
||||||
|
fn from(it: $variant$(<$V>)?) -> $enum$(<$V>)? {
|
||||||
|
$enum::$variant(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,10 @@ struct EntryPtr(EntryId, usize);
|
||||||
/// Internal type which is used instead of `TokenTree` to represent a token tree
|
/// Internal type which is used instead of `TokenTree` to represent a token tree
|
||||||
/// within a `TokenBuffer`.
|
/// within a `TokenBuffer`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Entry<'t> {
|
enum Entry<'t, Span> {
|
||||||
// Mimicking types from proc-macro.
|
// Mimicking types from proc-macro.
|
||||||
Subtree(Option<&'t TokenTree>, &'t Subtree, EntryId),
|
Subtree(Option<&'t TokenTree<Span>>, &'t Subtree<Span>, EntryId),
|
||||||
Leaf(&'t TokenTree),
|
Leaf(&'t TokenTree<Span>),
|
||||||
// End entries contain a pointer to the entry from the containing
|
// End entries contain a pointer to the entry from the containing
|
||||||
// token tree, or None if this is the outermost level.
|
// token tree, or None if this is the outermost level.
|
||||||
End(Option<EntryPtr>),
|
End(Option<EntryPtr>),
|
||||||
|
@ -24,16 +24,21 @@ enum Entry<'t> {
|
||||||
/// A token tree buffer
|
/// A token tree buffer
|
||||||
/// The safe version of `syn` [`TokenBuffer`](https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L41)
|
/// The safe version of `syn` [`TokenBuffer`](https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L41)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TokenBuffer<'t> {
|
pub struct TokenBuffer<'t, Span> {
|
||||||
buffers: Vec<Box<[Entry<'t>]>>,
|
buffers: Vec<Box<[Entry<'t, Span>]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
trait TokenList<'a> {
|
trait TokenList<'a, Span> {
|
||||||
fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>);
|
fn entries(
|
||||||
|
&self,
|
||||||
|
) -> (Vec<(usize, (&'a Subtree<Span>, Option<&'a TokenTree<Span>>))>, Vec<Entry<'a, Span>>);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TokenList<'a> for &'a [TokenTree] {
|
impl<'a, Span> TokenList<'a, Span> for &'a [TokenTree<Span>] {
|
||||||
fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>) {
|
fn entries(
|
||||||
|
&self,
|
||||||
|
) -> (Vec<(usize, (&'a Subtree<Span>, Option<&'a TokenTree<Span>>))>, Vec<Entry<'a, Span>>)
|
||||||
|
{
|
||||||
// Must contain everything in tokens and then the Entry::End
|
// Must contain everything in tokens and then the Entry::End
|
||||||
let start_capacity = self.len() + 1;
|
let start_capacity = self.len() + 1;
|
||||||
let mut entries = Vec::with_capacity(start_capacity);
|
let mut entries = Vec::with_capacity(start_capacity);
|
||||||
|
@ -53,8 +58,11 @@ impl<'a> TokenList<'a> for &'a [TokenTree] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TokenList<'a> for &'a Subtree {
|
impl<'a, Span> TokenList<'a, Span> for &'a Subtree<Span> {
|
||||||
fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>) {
|
fn entries(
|
||||||
|
&self,
|
||||||
|
) -> (Vec<(usize, (&'a Subtree<Span>, Option<&'a TokenTree<Span>>))>, Vec<Entry<'a, Span>>)
|
||||||
|
{
|
||||||
// Must contain everything in tokens and then the Entry::End
|
// Must contain everything in tokens and then the Entry::End
|
||||||
let mut entries = vec![];
|
let mut entries = vec![];
|
||||||
let mut children = vec![];
|
let mut children = vec![];
|
||||||
|
@ -64,25 +72,25 @@ impl<'a> TokenList<'a> for &'a Subtree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'t> TokenBuffer<'t> {
|
impl<'t, Span> TokenBuffer<'t, Span> {
|
||||||
pub fn from_tokens(tokens: &'t [TokenTree]) -> TokenBuffer<'t> {
|
pub fn from_tokens(tokens: &'t [TokenTree<Span>]) -> TokenBuffer<'t, Span> {
|
||||||
Self::new(tokens)
|
Self::new(tokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_subtree(subtree: &'t Subtree) -> TokenBuffer<'t> {
|
pub fn from_subtree(subtree: &'t Subtree<Span>) -> TokenBuffer<'t, Span> {
|
||||||
Self::new(subtree)
|
Self::new(subtree)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new<T: TokenList<'t>>(tokens: T) -> TokenBuffer<'t> {
|
fn new<T: TokenList<'t, Span>>(tokens: T) -> TokenBuffer<'t, Span> {
|
||||||
let mut buffers = vec![];
|
let mut buffers = vec![];
|
||||||
let idx = TokenBuffer::new_inner(tokens, &mut buffers, None);
|
let idx = TokenBuffer::new_inner(tokens, &mut buffers, None);
|
||||||
assert_eq!(idx, 0);
|
assert_eq!(idx, 0);
|
||||||
TokenBuffer { buffers }
|
TokenBuffer { buffers }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_inner<T: TokenList<'t>>(
|
fn new_inner<T: TokenList<'t, Span>>(
|
||||||
tokens: T,
|
tokens: T,
|
||||||
buffers: &mut Vec<Box<[Entry<'t>]>>,
|
buffers: &mut Vec<Box<[Entry<'t, Span>]>>,
|
||||||
next: Option<EntryPtr>,
|
next: Option<EntryPtr>,
|
||||||
) -> usize {
|
) -> usize {
|
||||||
let (children, mut entries) = tokens.entries();
|
let (children, mut entries) = tokens.entries();
|
||||||
|
@ -105,25 +113,25 @@ impl<'t> TokenBuffer<'t> {
|
||||||
|
|
||||||
/// Creates a cursor referencing the first token in the buffer and able to
|
/// Creates a cursor referencing the first token in the buffer and able to
|
||||||
/// traverse until the end of the buffer.
|
/// traverse until the end of the buffer.
|
||||||
pub fn begin(&self) -> Cursor<'_> {
|
pub fn begin(&self) -> Cursor<'_, Span> {
|
||||||
Cursor::create(self, EntryPtr(EntryId(0), 0))
|
Cursor::create(self, EntryPtr(EntryId(0), 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn entry(&self, ptr: &EntryPtr) -> Option<&Entry<'_>> {
|
fn entry(&self, ptr: &EntryPtr) -> Option<&Entry<'_, Span>> {
|
||||||
let id = ptr.0;
|
let id = ptr.0;
|
||||||
self.buffers[id.0].get(ptr.1)
|
self.buffers[id.0].get(ptr.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TokenTreeRef<'a> {
|
pub enum TokenTreeRef<'a, Span> {
|
||||||
Subtree(&'a Subtree, Option<&'a TokenTree>),
|
Subtree(&'a Subtree<Span>, Option<&'a TokenTree<Span>>),
|
||||||
Leaf(&'a Leaf, &'a TokenTree),
|
Leaf(&'a Leaf<Span>, &'a TokenTree<Span>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TokenTreeRef<'a> {
|
impl<'a, Span: Clone> TokenTreeRef<'a, Span> {
|
||||||
pub fn cloned(&self) -> TokenTree {
|
pub fn cloned(&self) -> TokenTree<Span> {
|
||||||
match &self {
|
match self {
|
||||||
TokenTreeRef::Subtree(subtree, tt) => match tt {
|
TokenTreeRef::Subtree(subtree, tt) => match tt {
|
||||||
Some(it) => (*it).clone(),
|
Some(it) => (*it).clone(),
|
||||||
None => (*subtree).clone().into(),
|
None => (*subtree).clone().into(),
|
||||||
|
@ -135,20 +143,20 @@ impl<'a> TokenTreeRef<'a> {
|
||||||
|
|
||||||
/// A safe version of `Cursor` from `syn` crate <https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L125>
|
/// A safe version of `Cursor` from `syn` crate <https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L125>
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Cursor<'a> {
|
pub struct Cursor<'a, Span> {
|
||||||
buffer: &'a TokenBuffer<'a>,
|
buffer: &'a TokenBuffer<'a, Span>,
|
||||||
ptr: EntryPtr,
|
ptr: EntryPtr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PartialEq for Cursor<'a> {
|
impl<'a, Span> PartialEq for Cursor<'a, Span> {
|
||||||
fn eq(&self, other: &Cursor<'_>) -> bool {
|
fn eq(&self, other: &Cursor<'_, Span>) -> bool {
|
||||||
self.ptr == other.ptr && std::ptr::eq(self.buffer, other.buffer)
|
self.ptr == other.ptr && std::ptr::eq(self.buffer, other.buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Eq for Cursor<'a> {}
|
impl<'a, Span> Eq for Cursor<'a, Span> {}
|
||||||
|
|
||||||
impl<'a> Cursor<'a> {
|
impl<'a, Span> Cursor<'a, Span> {
|
||||||
/// Check whether it is eof
|
/// Check whether it is eof
|
||||||
pub fn eof(self) -> bool {
|
pub fn eof(self) -> bool {
|
||||||
matches!(self.buffer.entry(&self.ptr), None | Some(Entry::End(None)))
|
matches!(self.buffer.entry(&self.ptr), None | Some(Entry::End(None)))
|
||||||
|
@ -156,7 +164,7 @@ impl<'a> Cursor<'a> {
|
||||||
|
|
||||||
/// If the cursor is pointing at the end of a subtree, returns
|
/// If the cursor is pointing at the end of a subtree, returns
|
||||||
/// the parent subtree
|
/// the parent subtree
|
||||||
pub fn end(self) -> Option<&'a Subtree> {
|
pub fn end(self) -> Option<&'a Subtree<Span>> {
|
||||||
match self.entry() {
|
match self.entry() {
|
||||||
Some(Entry::End(Some(ptr))) => {
|
Some(Entry::End(Some(ptr))) => {
|
||||||
let idx = ptr.1;
|
let idx = ptr.1;
|
||||||
|
@ -171,13 +179,13 @@ impl<'a> Cursor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn entry(self) -> Option<&'a Entry<'a>> {
|
fn entry(&self) -> Option<&'a Entry<'a, Span>> {
|
||||||
self.buffer.entry(&self.ptr)
|
self.buffer.entry(&self.ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the cursor is pointing at a `Subtree`, returns
|
/// If the cursor is pointing at a `Subtree`, returns
|
||||||
/// a cursor into that subtree
|
/// a cursor into that subtree
|
||||||
pub fn subtree(self) -> Option<Cursor<'a>> {
|
pub fn subtree(self) -> Option<Cursor<'a, Span>> {
|
||||||
match self.entry() {
|
match self.entry() {
|
||||||
Some(Entry::Subtree(_, _, entry_id)) => {
|
Some(Entry::Subtree(_, _, entry_id)) => {
|
||||||
Some(Cursor::create(self.buffer, EntryPtr(*entry_id, 0)))
|
Some(Cursor::create(self.buffer, EntryPtr(*entry_id, 0)))
|
||||||
|
@ -187,7 +195,7 @@ impl<'a> Cursor<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the cursor is pointing at a `TokenTree`, returns it
|
/// If the cursor is pointing at a `TokenTree`, returns it
|
||||||
pub fn token_tree(self) -> Option<TokenTreeRef<'a>> {
|
pub fn token_tree(self) -> Option<TokenTreeRef<'a, Span>> {
|
||||||
match self.entry() {
|
match self.entry() {
|
||||||
Some(Entry::Leaf(tt)) => match tt {
|
Some(Entry::Leaf(tt)) => match tt {
|
||||||
TokenTree::Leaf(leaf) => Some(TokenTreeRef::Leaf(leaf, tt)),
|
TokenTree::Leaf(leaf) => Some(TokenTreeRef::Leaf(leaf, tt)),
|
||||||
|
@ -198,12 +206,12 @@ impl<'a> Cursor<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create(buffer: &'a TokenBuffer<'_>, ptr: EntryPtr) -> Cursor<'a> {
|
fn create(buffer: &'a TokenBuffer<'_, Span>, ptr: EntryPtr) -> Cursor<'a, Span> {
|
||||||
Cursor { buffer, ptr }
|
Cursor { buffer, ptr }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bump the cursor
|
/// Bump the cursor
|
||||||
pub fn bump(self) -> Cursor<'a> {
|
pub fn bump(self) -> Cursor<'a, Span> {
|
||||||
if let Some(Entry::End(exit)) = self.buffer.entry(&self.ptr) {
|
if let Some(Entry::End(exit)) = self.buffer.entry(&self.ptr) {
|
||||||
match exit {
|
match exit {
|
||||||
Some(exit) => Cursor::create(self.buffer, *exit),
|
Some(exit) => Cursor::create(self.buffer, *exit),
|
||||||
|
@ -216,7 +224,7 @@ impl<'a> Cursor<'a> {
|
||||||
|
|
||||||
/// Bump the cursor, if it is a subtree, returns
|
/// Bump the cursor, if it is a subtree, returns
|
||||||
/// a cursor into that subtree
|
/// a cursor into that subtree
|
||||||
pub fn bump_subtree(self) -> Cursor<'a> {
|
pub fn bump_subtree(self) -> Cursor<'a, Span> {
|
||||||
match self.entry() {
|
match self.entry() {
|
||||||
Some(Entry::Subtree(_, _, _)) => self.subtree().unwrap(),
|
Some(Entry::Subtree(_, _, _)) => self.subtree().unwrap(),
|
||||||
_ => self.bump(),
|
_ => self.bump(),
|
||||||
|
|
|
@ -16,45 +16,106 @@ pub use smol_str::SmolStr;
|
||||||
/// which source tokens. We do it by assigning an distinct identity to each
|
/// which source tokens. We do it by assigning an distinct identity to each
|
||||||
/// source token and making sure that identities are preserved during macro
|
/// source token and making sure that identities are preserved during macro
|
||||||
/// expansion.
|
/// expansion.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct TokenId(pub u32);
|
pub struct TokenId(pub u32);
|
||||||
|
|
||||||
|
impl fmt::Debug for TokenId {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TokenId {
|
impl TokenId {
|
||||||
|
pub const UNSPECIFIED: TokenId = TokenId(!0);
|
||||||
pub const fn unspecified() -> TokenId {
|
pub const fn unspecified() -> TokenId {
|
||||||
TokenId(!0)
|
Self::UNSPECIFIED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
pub mod token_id {
|
||||||
pub enum TokenTree {
|
pub use crate::{DelimiterKind, Spacing, TokenId};
|
||||||
Leaf(Leaf),
|
pub type Span = crate::TokenId;
|
||||||
Subtree(Subtree),
|
pub type Subtree = crate::Subtree<Span>;
|
||||||
}
|
pub type Punct = crate::Punct<Span>;
|
||||||
impl_from!(Leaf, Subtree for TokenTree);
|
pub type Delimiter = crate::Delimiter<Span>;
|
||||||
|
pub type Leaf = crate::Leaf<Span>;
|
||||||
|
pub type Ident = crate::Ident<Span>;
|
||||||
|
pub type Literal = crate::Literal<Span>;
|
||||||
|
pub type TokenTree = crate::TokenTree<Span>;
|
||||||
|
pub mod buffer {
|
||||||
|
pub type TokenBuffer<'a> = crate::buffer::TokenBuffer<'a, super::Span>;
|
||||||
|
pub type Cursor<'a> = crate::buffer::Cursor<'a, super::Span>;
|
||||||
|
pub type TokenTreeRef<'a> = crate::buffer::TokenTreeRef<'a, super::Span>;
|
||||||
|
}
|
||||||
|
|
||||||
impl TokenTree {
|
impl Delimiter {
|
||||||
pub fn empty() -> Self {
|
pub const UNSPECIFIED: Self = Self {
|
||||||
TokenTree::Subtree(Subtree::default())
|
open: TokenId::UNSPECIFIED,
|
||||||
|
close: TokenId::UNSPECIFIED,
|
||||||
|
kind: DelimiterKind::Invisible,
|
||||||
|
};
|
||||||
|
pub const fn unspecified() -> Self {
|
||||||
|
Self::UNSPECIFIED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Subtree {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Subtree { delimiter: Delimiter::unspecified(), token_trees: vec![] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl TokenTree {
|
||||||
|
pub const fn empty() -> Self {
|
||||||
|
Self::Subtree(Subtree { delimiter: Delimiter::unspecified(), token_trees: vec![] })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub enum Leaf {
|
pub struct SyntaxContext(pub u32);
|
||||||
Literal(Literal),
|
|
||||||
Punct(Punct),
|
|
||||||
Ident(Ident),
|
|
||||||
}
|
|
||||||
impl_from!(Literal, Punct, Ident for Leaf);
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Default)]
|
// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct Subtree {
|
// pub struct Span {
|
||||||
pub delimiter: Option<Delimiter>,
|
// pub id: TokenId,
|
||||||
pub token_trees: Vec<TokenTree>,
|
// pub ctx: SyntaxContext,
|
||||||
|
// }
|
||||||
|
// pub type Span = (TokenId, SyntaxContext);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TokenTree<Span> {
|
||||||
|
Leaf(Leaf<Span>),
|
||||||
|
Subtree(Subtree<Span>),
|
||||||
|
}
|
||||||
|
impl_from!(Leaf<Span>, Subtree<Span> for TokenTree);
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub enum Leaf<Span> {
|
||||||
|
Literal(Literal<Span>),
|
||||||
|
Punct(Punct<Span>),
|
||||||
|
Ident(Ident<Span>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Span> Leaf<Span> {
|
||||||
|
pub fn span(&self) -> &Span {
|
||||||
|
match self {
|
||||||
|
Leaf::Literal(it) => &it.span,
|
||||||
|
Leaf::Punct(it) => &it.span,
|
||||||
|
Leaf::Ident(it) => &it.span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl_from!(Literal<Span>, Punct<Span>, Ident<Span> for Leaf);
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Subtree<Span> {
|
||||||
|
// FIXME, this should not be Option
|
||||||
|
pub delimiter: Delimiter<Span>,
|
||||||
|
pub token_trees: Vec<TokenTree<Span>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Delimiter {
|
pub struct Delimiter<Span> {
|
||||||
pub id: TokenId,
|
pub open: Span,
|
||||||
|
pub close: Span,
|
||||||
pub kind: DelimiterKind,
|
pub kind: DelimiterKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,19 +124,20 @@ pub enum DelimiterKind {
|
||||||
Parenthesis,
|
Parenthesis,
|
||||||
Brace,
|
Brace,
|
||||||
Bracket,
|
Bracket,
|
||||||
|
Invisible,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Literal {
|
pub struct Literal<Span> {
|
||||||
pub text: SmolStr,
|
pub text: SmolStr,
|
||||||
pub id: TokenId,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
pub struct Punct {
|
pub struct Punct<Span> {
|
||||||
pub char: char,
|
pub char: char,
|
||||||
pub spacing: Spacing,
|
pub spacing: Spacing,
|
||||||
pub id: TokenId,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
@ -85,39 +147,25 @@ pub enum Spacing {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Ident {
|
/// Identifier or keyword. Unlike rustc, we keep "r#" prefix when it represents a raw identifier.
|
||||||
/// Identifier or keyword. Unlike rustc, we keep "r#" prefix when it represents a raw identifier.
|
pub struct Ident<Span> {
|
||||||
pub text: SmolStr,
|
pub text: SmolStr,
|
||||||
pub id: TokenId,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ident {
|
fn print_debug_subtree<Span: fmt::Debug>(
|
||||||
/// Constructor intended to be used only by proc macro server. `text` should not contain raw
|
f: &mut fmt::Formatter<'_>,
|
||||||
/// identifier prefix.
|
subtree: &Subtree<Span>,
|
||||||
pub fn new_with_is_raw(text: SmolStr, id: TokenId, is_raw: bool) -> Self {
|
level: usize,
|
||||||
let text = if is_raw { SmolStr::from_iter(["r#", &text]) } else { text };
|
) -> fmt::Result {
|
||||||
Ident { text, id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Leaf {
|
|
||||||
pub fn id(&self) -> TokenId {
|
|
||||||
match self {
|
|
||||||
Leaf::Literal(l) => l.id,
|
|
||||||
Leaf::Punct(p) => p.id,
|
|
||||||
Leaf::Ident(i) => i.id,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_debug_subtree(f: &mut fmt::Formatter<'_>, subtree: &Subtree, level: usize) -> fmt::Result {
|
|
||||||
let align = " ".repeat(level);
|
let align = " ".repeat(level);
|
||||||
|
|
||||||
let aux = match subtree.delimiter.map(|it| (it.kind, it.id.0)) {
|
let Delimiter { kind, open, close } = &subtree.delimiter;
|
||||||
None => "$".to_string(),
|
let aux = match kind {
|
||||||
Some((DelimiterKind::Parenthesis, id)) => format!("() {id}"),
|
DelimiterKind::Invisible => format!("$$ {:?} {:?}", open, close),
|
||||||
Some((DelimiterKind::Brace, id)) => format!("{{}} {id}"),
|
DelimiterKind::Parenthesis => format!("() {:?} {:?}", open, close),
|
||||||
Some((DelimiterKind::Bracket, id)) => format!("[] {id}"),
|
DelimiterKind::Brace => format!("{{}} {:?} {:?}", open, close),
|
||||||
|
DelimiterKind::Bracket => format!("[] {:?} {:?}", open, close),
|
||||||
};
|
};
|
||||||
|
|
||||||
if subtree.token_trees.is_empty() {
|
if subtree.token_trees.is_empty() {
|
||||||
|
@ -135,21 +183,25 @@ fn print_debug_subtree(f: &mut fmt::Formatter<'_>, subtree: &Subtree, level: usi
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_debug_token(f: &mut fmt::Formatter<'_>, tkn: &TokenTree, level: usize) -> fmt::Result {
|
fn print_debug_token<Span: fmt::Debug>(
|
||||||
|
f: &mut fmt::Formatter<'_>,
|
||||||
|
tkn: &TokenTree<Span>,
|
||||||
|
level: usize,
|
||||||
|
) -> fmt::Result {
|
||||||
let align = " ".repeat(level);
|
let align = " ".repeat(level);
|
||||||
|
|
||||||
match tkn {
|
match tkn {
|
||||||
TokenTree::Leaf(leaf) => match leaf {
|
TokenTree::Leaf(leaf) => match leaf {
|
||||||
Leaf::Literal(lit) => write!(f, "{align}LITERAL {} {}", lit.text, lit.id.0)?,
|
Leaf::Literal(lit) => write!(f, "{}LITERAL {} {:?}", align, lit.text, lit.span)?,
|
||||||
Leaf::Punct(punct) => write!(
|
Leaf::Punct(punct) => write!(
|
||||||
f,
|
f,
|
||||||
"{}PUNCH {} [{}] {}",
|
"{}PUNCH {} [{}] {:?}",
|
||||||
align,
|
align,
|
||||||
punct.char,
|
punct.char,
|
||||||
if punct.spacing == Spacing::Alone { "alone" } else { "joint" },
|
if punct.spacing == Spacing::Alone { "alone" } else { "joint" },
|
||||||
punct.id.0
|
punct.span
|
||||||
)?,
|
)?,
|
||||||
Leaf::Ident(ident) => write!(f, "{align}IDENT {} {}", ident.text, ident.id.0)?,
|
Leaf::Ident(ident) => write!(f, "{}IDENT {} {:?}", align, ident.text, ident.span)?,
|
||||||
},
|
},
|
||||||
TokenTree::Subtree(subtree) => {
|
TokenTree::Subtree(subtree) => {
|
||||||
print_debug_subtree(f, subtree, level)?;
|
print_debug_subtree(f, subtree, level)?;
|
||||||
|
@ -159,13 +211,13 @@ fn print_debug_token(f: &mut fmt::Formatter<'_>, tkn: &TokenTree, level: usize)
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Subtree {
|
impl<Span: fmt::Debug> fmt::Debug for Subtree<Span> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
print_debug_subtree(f, self, 0)
|
print_debug_subtree(f, self, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TokenTree {
|
impl<Span> fmt::Display for TokenTree<Span> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
TokenTree::Leaf(it) => fmt::Display::fmt(it, f),
|
TokenTree::Leaf(it) => fmt::Display::fmt(it, f),
|
||||||
|
@ -174,13 +226,13 @@ impl fmt::Display for TokenTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Subtree {
|
impl<Span> fmt::Display for Subtree<Span> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
let (l, r) = match self.delimiter_kind() {
|
let (l, r) = match self.delimiter.kind {
|
||||||
Some(DelimiterKind::Parenthesis) => ("(", ")"),
|
DelimiterKind::Parenthesis => ("(", ")"),
|
||||||
Some(DelimiterKind::Brace) => ("{", "}"),
|
DelimiterKind::Brace => ("{", "}"),
|
||||||
Some(DelimiterKind::Bracket) => ("[", "]"),
|
DelimiterKind::Bracket => ("[", "]"),
|
||||||
None => ("", ""),
|
DelimiterKind::Invisible => ("", ""),
|
||||||
};
|
};
|
||||||
f.write_str(l)?;
|
f.write_str(l)?;
|
||||||
let mut needs_space = false;
|
let mut needs_space = false;
|
||||||
|
@ -202,7 +254,7 @@ impl fmt::Display for Subtree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Leaf {
|
impl<Span> fmt::Display for Leaf<Span> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Leaf::Ident(it) => fmt::Display::fmt(it, f),
|
Leaf::Ident(it) => fmt::Display::fmt(it, f),
|
||||||
|
@ -212,25 +264,25 @@ impl fmt::Display for Leaf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Ident {
|
impl<Span> fmt::Display for Ident<Span> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Display::fmt(&self.text, f)
|
fmt::Display::fmt(&self.text, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Literal {
|
impl<Span> fmt::Display for Literal<Span> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Display::fmt(&self.text, f)
|
fmt::Display::fmt(&self.text, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Punct {
|
impl<Span> fmt::Display for Punct<Span> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Display::fmt(&self.char, f)
|
fmt::Display::fmt(&self.char, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Subtree {
|
impl<Span> Subtree<Span> {
|
||||||
/// Count the number of tokens recursively
|
/// Count the number of tokens recursively
|
||||||
pub fn count(&self) -> usize {
|
pub fn count(&self) -> usize {
|
||||||
let children_count = self
|
let children_count = self
|
||||||
|
@ -244,20 +296,16 @@ impl Subtree {
|
||||||
|
|
||||||
self.token_trees.len() + children_count
|
self.token_trees.len() + children_count
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delimiter_kind(&self) -> Option<DelimiterKind> {
|
|
||||||
self.delimiter.map(|it| it.kind)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Subtree {
|
impl<Span> Subtree<Span> {
|
||||||
/// A simple line string used for debugging
|
/// A simple line string used for debugging
|
||||||
pub fn as_debug_string(&self) -> String {
|
pub fn as_debug_string(&self) -> String {
|
||||||
let delim = match self.delimiter_kind() {
|
let delim = match self.delimiter.kind {
|
||||||
Some(DelimiterKind::Brace) => ("{", "}"),
|
DelimiterKind::Brace => ("{", "}"),
|
||||||
Some(DelimiterKind::Bracket) => ("[", "]"),
|
DelimiterKind::Bracket => ("[", "]"),
|
||||||
Some(DelimiterKind::Parenthesis) => ("(", ")"),
|
DelimiterKind::Parenthesis => ("(", ")"),
|
||||||
None => (" ", " "),
|
DelimiterKind::Invisible => ("$", "$"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut res = String::new();
|
let mut res = String::new();
|
||||||
|
@ -275,7 +323,7 @@ impl Subtree {
|
||||||
(Leaf::Ident(_), Some(&TokenTree::Leaf(Leaf::Ident(_)))) => {
|
(Leaf::Ident(_), Some(&TokenTree::Leaf(Leaf::Ident(_)))) => {
|
||||||
" ".to_string() + &s
|
" ".to_string() + &s
|
||||||
}
|
}
|
||||||
(Leaf::Punct(_), Some(&TokenTree::Leaf(Leaf::Punct(punct)))) => {
|
(Leaf::Punct(_), Some(TokenTree::Leaf(Leaf::Punct(punct)))) => {
|
||||||
if punct.spacing == Spacing::Alone {
|
if punct.spacing == Spacing::Alone {
|
||||||
" ".to_string() + &s
|
" ".to_string() + &s
|
||||||
} else {
|
} else {
|
||||||
|
@ -298,19 +346,19 @@ impl Subtree {
|
||||||
|
|
||||||
pub mod buffer;
|
pub mod buffer;
|
||||||
|
|
||||||
pub fn pretty(tkns: &[TokenTree]) -> String {
|
pub fn pretty<Span>(tkns: &[TokenTree<Span>]) -> String {
|
||||||
fn tokentree_to_text(tkn: &TokenTree) -> String {
|
fn tokentree_to_text<Span>(tkn: &TokenTree<Span>) -> String {
|
||||||
match tkn {
|
match tkn {
|
||||||
TokenTree::Leaf(Leaf::Ident(ident)) => ident.text.clone().into(),
|
TokenTree::Leaf(Leaf::Ident(ident)) => ident.text.clone().into(),
|
||||||
TokenTree::Leaf(Leaf::Literal(literal)) => literal.text.clone().into(),
|
TokenTree::Leaf(Leaf::Literal(literal)) => literal.text.clone().into(),
|
||||||
TokenTree::Leaf(Leaf::Punct(punct)) => format!("{}", punct.char),
|
TokenTree::Leaf(Leaf::Punct(punct)) => format!("{}", punct.char),
|
||||||
TokenTree::Subtree(subtree) => {
|
TokenTree::Subtree(subtree) => {
|
||||||
let content = pretty(&subtree.token_trees);
|
let content = pretty(&subtree.token_trees);
|
||||||
let (open, close) = match subtree.delimiter.map(|it| it.kind) {
|
let (open, close) = match subtree.delimiter.kind {
|
||||||
None => ("", ""),
|
DelimiterKind::Brace => ("{", "}"),
|
||||||
Some(DelimiterKind::Brace) => ("{", "}"),
|
DelimiterKind::Bracket => ("[", "]"),
|
||||||
Some(DelimiterKind::Parenthesis) => ("(", ")"),
|
DelimiterKind::Parenthesis => ("(", ")"),
|
||||||
Some(DelimiterKind::Bracket) => ("[", "]"),
|
DelimiterKind::Invisible => ("", ""),
|
||||||
};
|
};
|
||||||
format!("{open}{content}{close}")
|
format!("{open}{content}{close}")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue