Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-expand/src/builtin/fn_macro.rs')
| -rw-r--r-- | crates/hir-expand/src/builtin/fn_macro.rs | 95 |
1 files changed, 55 insertions, 40 deletions
diff --git a/crates/hir-expand/src/builtin/fn_macro.rs b/crates/hir-expand/src/builtin/fn_macro.rs index 3180b8dae1..60fbc66065 100644 --- a/crates/hir-expand/src/builtin/fn_macro.rs +++ b/crates/hir-expand/src/builtin/fn_macro.rs @@ -7,12 +7,13 @@ use intern::{ Symbol, sym::{self}, }; +use itertools::Itertools; use mbe::{DelimiterKind, expect_fragment}; use span::{Edition, FileId, Span}; use stdx::format_to; use syntax::{ format_smolstr, - unescape::{Mode, unescape_byte, unescape_char, unescape_unicode}, + unescape::{unescape_byte, unescape_char, unescape_str}, }; use syntax_bridge::syntax_node_to_token_tree; @@ -124,8 +125,8 @@ register_builtin! { (assert, Assert) => assert_expand, (stringify, Stringify) => stringify_expand, (asm, Asm) => asm_expand, - (global_asm, GlobalAsm) => asm_expand, - (naked_asm, NakedAsm) => asm_expand, + (global_asm, GlobalAsm) => global_asm_expand, + (naked_asm, NakedAsm) => naked_asm_expand, (cfg, Cfg) => cfg_expand, (core_panic, CorePanic) => panic_expand, (std_panic, StdPanic) => panic_expand, @@ -324,6 +325,36 @@ fn asm_expand( ExpandResult::ok(expanded) } +fn global_asm_expand( + _db: &dyn ExpandDatabase, + _id: MacroCallId, + tt: &tt::TopSubtree, + span: Span, +) -> ExpandResult<tt::TopSubtree> { + let mut tt = tt.clone(); + tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis; + let pound = mk_pound(span); + let expanded = quote! {span => + builtin #pound global_asm #tt + }; + ExpandResult::ok(expanded) +} + +fn naked_asm_expand( + _db: &dyn ExpandDatabase, + _id: MacroCallId, + tt: &tt::TopSubtree, + span: Span, +) -> ExpandResult<tt::TopSubtree> { + let mut tt = tt.clone(); + tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis; + let pound = mk_pound(span); + let expanded = quote! {span => + builtin #pound naked_asm #tt + }; + ExpandResult::ok(expanded) +} + fn cfg_expand( db: &dyn ExpandDatabase, id: MacroCallId, @@ -430,7 +461,7 @@ fn compile_error_expand( kind: tt::LitKind::Str | tt::LitKind::StrRaw(_), suffix: _, })), - ] => ExpandError::other(span, Box::from(unescape_str(text).as_str())), + ] => ExpandError::other(span, Box::from(unescape_symbol(text).as_str())), _ => ExpandError::other(span, "`compile_error!` argument must be a string"), }; @@ -481,7 +512,7 @@ fn concat_expand( format_to!(text, "{}", it.symbol.as_str()) } tt::LitKind::Str => { - text.push_str(unescape_str(&it.symbol).as_str()); + text.push_str(unescape_symbol(&it.symbol).as_str()); record_span(it.span); } tt::LitKind::StrRaw(_) => { @@ -681,52 +712,36 @@ fn relative_file( } fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> { - let delimiter = tt.top_subtree().delimiter; - tt.iter() - .next() - .ok_or(delimiter.open.cover(delimiter.close)) - .and_then(|tt| match tt { + let mut tt = TtElement::Subtree(tt.top_subtree(), tt.iter()); + (|| { + // FIXME: We wrap expression fragments in parentheses which can break this expectation + // here + // Remove this once we handle none delims correctly + while let TtElement::Subtree(sub, tt_iter) = &mut tt + && let DelimiterKind::Parenthesis | DelimiterKind::Invisible = sub.delimiter.kind + { + tt = + tt_iter.exactly_one().map_err(|_| sub.delimiter.open.cover(sub.delimiter.close))?; + } + + match tt { TtElement::Leaf(tt::Leaf::Literal(tt::Literal { symbol: text, span, kind: tt::LitKind::Str, suffix: _, - })) => Ok((unescape_str(text), *span)), + })) => Ok((unescape_symbol(text), *span)), TtElement::Leaf(tt::Leaf::Literal(tt::Literal { symbol: text, span, kind: tt::LitKind::StrRaw(_), suffix: _, })) => Ok((text.clone(), *span)), - // FIXME: We wrap expression fragments in parentheses which can break this expectation - // here - // Remove this once we handle none delims correctly - TtElement::Subtree(tt, mut tt_iter) - if tt.delimiter.kind == DelimiterKind::Parenthesis => - { - tt_iter - .next() - .and_then(|tt| match tt { - TtElement::Leaf(tt::Leaf::Literal(tt::Literal { - symbol: text, - span, - kind: tt::LitKind::Str, - suffix: _, - })) => Some((unescape_str(text), *span)), - TtElement::Leaf(tt::Leaf::Literal(tt::Literal { - symbol: text, - span, - kind: tt::LitKind::StrRaw(_), - suffix: _, - })) => Some((text.clone(), *span)), - _ => None, - }) - .ok_or(delimiter.open.cover(delimiter.close)) - } TtElement::Leaf(l) => Err(*l.span()), TtElement::Subtree(tt, _) => Err(tt.delimiter.open.cover(tt.delimiter.close)), - }) - .map_err(|span| ExpandError::other(span, "expected string literal")) + } + })() + .map_err(|span| ExpandError::other(span, "expected string literal")) } fn include_expand( @@ -897,11 +912,11 @@ fn quote_expand( ) } -fn unescape_str(s: &Symbol) -> Symbol { +fn unescape_symbol(s: &Symbol) -> Symbol { if s.as_str().contains('\\') { let s = s.as_str(); let mut buf = String::with_capacity(s.len()); - unescape_unicode(s, Mode::Str, &mut |_, c| { + unescape_str(s, |_, c| { if let Ok(c) = c { buf.push(c) } |