This commit is contained in:
Aleksey Kladov 2019-01-02 16:00:01 +03:00
parent 4fe0ec5497
commit 35b3fc02e0
3 changed files with 36 additions and 13 deletions

View File

@ -29,6 +29,8 @@ use crate::{
pub struct HirFileId(HirFileIdRepr);
impl HirFileId {
/// For macro-expansion files, returns the file original source file the
/// expansionoriginated from.
pub(crate) fn original_file_id(self, db: &impl HirDatabase) -> FileId {
match self.0 {
HirFileIdRepr::File(file_id) => file_id,
@ -45,6 +47,7 @@ impl HirFileId {
HirFileIdRepr::Macro(_r) => panic!("macro generated file: {:?}", self),
}
}
pub(crate) fn hir_source_file(db: &impl HirDatabase, file_id: HirFileId) -> SourceFileNode {
match file_id.0 {
HirFileIdRepr::File(file_id) => db.source_file(file_id),

View File

@ -25,6 +25,7 @@ pub mod source_binder;
mod ids;
mod macros;
mod name;
// can't use `crate` or `r#crate` here :(
mod krate;
mod module;
mod function;

View File

@ -1,3 +1,12 @@
/// Machinery for macro expansion.
///
/// One of the more complicated things about macros is managing the source code
/// that is produced after expansion. See `HirFileId` and `MacroCallId` for how
/// do we do that.
///
/// When file-management question is resolved, all that is left is a token tree
/// to token tree transformation plus hygent. We don't have either of thouse
/// yet, so all macros are string based at the moment!
use std::sync::Arc;
use ra_db::LocalSyntaxPtr;
@ -16,6 +25,8 @@ pub enum MacroDef {
}
impl MacroDef {
/// Expands macro call, returning the expansion and offset to be used to
/// convert ranges between expansion and original source.
pub fn ast_expand(macro_call: ast::MacroCall) -> Option<(TextUnit, MacroExpansion)> {
let (def, input) = MacroDef::from_call(macro_call)?;
let exp = def.expand(input)?;
@ -109,14 +120,20 @@ pub struct MacroInput {
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MacroExpansion {
/// The result of macro expansion. Should be token tree as well.
text: String,
/// Correspondence between ranges in the original source code and ranges in
/// the macro.
ranges_map: Vec<(TextRange, TextRange)>,
/// Implementation detail: internally, a macro is expanded to the whole file,
/// even if it is an expression. This `ptr` selects the actual expansion from
/// the expanded file.
ptr: LocalSyntaxPtr,
}
impl MacroExpansion {
//FIXME: does not really make sense, macro expansion is not neccessary a
//whole file.
// FIXME: does not really make sense, macro expansion is not neccessary a
// whole file. See `MacroExpansion::ptr` as well.
pub(crate) fn file(&self) -> SourceFileNode {
SourceFileNode::parse(&self.text)
}
@ -124,17 +141,7 @@ impl MacroExpansion {
pub fn syntax(&self) -> SyntaxNode {
self.ptr.resolve(&self.file())
}
pub fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> {
for (s_range, t_range) in self.ranges_map.iter() {
if tgt_range.is_subrange(&t_range) {
let tgt_at_zero_range = tgt_range - tgt_range.start();
let tgt_range_offset = tgt_range.start() - t_range.start();
let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start();
return Some(src_range);
}
}
None
}
/// Maps range in the source code to the range in the expanded code.
pub fn map_range_forward(&self, src_range: TextRange) -> Option<TextRange> {
for (s_range, t_range) in self.ranges_map.iter() {
if src_range.is_subrange(&s_range) {
@ -146,6 +153,18 @@ impl MacroExpansion {
}
None
}
/// Maps range in the expanded code to the range in the source code.
pub fn map_range_back(&self, tgt_range: TextRange) -> Option<TextRange> {
for (s_range, t_range) in self.ranges_map.iter() {
if tgt_range.is_subrange(&t_range) {
let tgt_at_zero_range = tgt_range - tgt_range.start();
let tgt_range_offset = tgt_range.start() - t_range.start();
let src_range = tgt_at_zero_range + tgt_range_offset + s_range.start();
return Some(src_range);
}
}
None
}
}
pub(crate) fn expand_macro_invocation(