2019-11-10 03:03:24 +00:00
|
|
|
//! Builtin macro
|
2019-11-11 06:15:09 +00:00
|
|
|
use crate::db::AstDatabase;
|
|
|
|
use crate::{
|
|
|
|
ast::{self, AstNode},
|
2019-11-11 10:45:55 +00:00
|
|
|
name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind,
|
2019-11-11 06:15:09 +00:00
|
|
|
TextUnit,
|
|
|
|
};
|
|
|
|
|
|
|
|
use crate::quote;
|
2019-11-10 03:03:24 +00:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
pub enum BuiltinExpander {
|
2019-11-11 06:15:09 +00:00
|
|
|
Line,
|
2019-11-10 03:03:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BuiltinExpander {
|
2019-11-11 06:15:09 +00:00
|
|
|
pub fn expand(
|
|
|
|
&self,
|
|
|
|
db: &dyn AstDatabase,
|
|
|
|
id: MacroCallId,
|
|
|
|
tt: &tt::Subtree,
|
|
|
|
) -> Result<tt::Subtree, mbe::ExpandError> {
|
|
|
|
match self {
|
|
|
|
BuiltinExpander::Line => line_expand(db, id, tt),
|
|
|
|
}
|
2019-11-10 03:03:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn find_builtin_macro(
|
|
|
|
ident: &name::Name,
|
|
|
|
krate: CrateId,
|
|
|
|
ast_id: AstId<ast::MacroCall>,
|
|
|
|
) -> Option<MacroDefId> {
|
|
|
|
// FIXME: Better registering method
|
2019-11-11 06:15:09 +00:00
|
|
|
if ident == &name::LINE_MACRO {
|
2019-11-11 10:45:55 +00:00
|
|
|
Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(BuiltinExpander::Line) })
|
2019-11-10 03:03:24 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
2019-11-11 06:15:09 +00:00
|
|
|
|
|
|
|
fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
|
|
|
|
// FIXME: Use expansion info
|
|
|
|
let file_id = file.original_file(db);
|
|
|
|
let text = db.file_text(file_id);
|
|
|
|
let mut line_num = 1;
|
|
|
|
|
|
|
|
// Count line end
|
|
|
|
for (i, c) in text.chars().enumerate() {
|
|
|
|
if i == pos.to_usize() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if c == '\n' {
|
|
|
|
line_num += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
line_num
|
|
|
|
}
|
|
|
|
|
|
|
|
fn line_expand(
|
|
|
|
db: &dyn AstDatabase,
|
|
|
|
id: MacroCallId,
|
|
|
|
_tt: &tt::Subtree,
|
|
|
|
) -> Result<tt::Subtree, mbe::ExpandError> {
|
|
|
|
let loc = db.lookup_intern_macro(id);
|
|
|
|
let macro_call = loc.ast_id.to_node(db);
|
|
|
|
|
|
|
|
let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
|
|
|
|
let arg_start = arg.syntax().text_range().start();
|
|
|
|
|
|
|
|
let file = id.as_file(MacroFileKind::Expr);
|
|
|
|
let line_num = to_line_number(db, file, arg_start);
|
|
|
|
|
|
|
|
let expanded = quote! {
|
|
|
|
#line_num
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(expanded)
|
|
|
|
}
|