mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Auto merge of #15559 - Veykril:builtin-format-args, r=Veykril
Implement builtin#format_args, using rustc's format_args parser `format_args!` now expands to `builtin#format_args(template, args...)`, the actual expansion now instead happens in lowering where we desugar this expression by using lang paths. As a bonus, we no longer need to evaluate `format_args` as an eager macro which means less macro expansions overall -> less cache thrashing! Fixes https://github.com/rust-lang/rust-analyzer/issues/15082
This commit is contained in:
commit
f29867bd26
40 changed files with 2581 additions and 476 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -541,6 +541,7 @@ dependencies = [
|
||||||
"mbe",
|
"mbe",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"profile",
|
"profile",
|
||||||
|
"ra-ap-rustc_lexer",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"stdx",
|
"stdx",
|
||||||
|
|
|
@ -33,6 +33,7 @@ triomphe.workspace = true
|
||||||
|
|
||||||
rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false }
|
rustc_abi = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_abi", default-features = false }
|
||||||
rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }
|
rustc_index = { version = "0.0.20221221", package = "hkalbasi-rustc-ap-rustc_index", default-features = false }
|
||||||
|
rustc_lexer = { version = "0.1.0", package = "ra-ap-rustc_lexer" }
|
||||||
|
|
||||||
# local deps
|
# local deps
|
||||||
stdx.workspace = true
|
stdx.workspace = true
|
||||||
|
|
|
@ -25,13 +25,20 @@ use triomphe::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
|
body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, LabelPtr, PatPtr},
|
||||||
|
builtin_type::BuiltinUint,
|
||||||
data::adt::StructKind,
|
data::adt::StructKind,
|
||||||
db::DefDatabase,
|
db::DefDatabase,
|
||||||
expander::Expander,
|
expander::Expander,
|
||||||
hir::{
|
hir::{
|
||||||
dummy_expr_id, Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy,
|
dummy_expr_id,
|
||||||
ClosureKind, Expr, ExprId, InlineAsm, Label, LabelId, Literal, LiteralOrConst, MatchArm,
|
format_args::{
|
||||||
Movability, OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
|
||||||
|
FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
|
||||||
|
FormatPlaceholder, FormatSign, FormatTrait,
|
||||||
|
},
|
||||||
|
Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
|
||||||
|
Expr, ExprId, InlineAsm, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
|
||||||
|
OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
|
||||||
},
|
},
|
||||||
item_scope::BuiltinShadowMode,
|
item_scope::BuiltinShadowMode,
|
||||||
lang_item::LangItem,
|
lang_item::LangItem,
|
||||||
|
@ -42,6 +49,8 @@ use crate::{
|
||||||
AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro,
|
AdtId, BlockId, BlockLoc, ConstBlockLoc, DefWithBodyId, ModuleDefId, UnresolvedMacro,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
|
||||||
|
|
||||||
pub(super) fn lower(
|
pub(super) fn lower(
|
||||||
db: &dyn DefDatabase,
|
db: &dyn DefDatabase,
|
||||||
owner: DefWithBodyId,
|
owner: DefWithBodyId,
|
||||||
|
@ -649,15 +658,15 @@ impl ExprCollector<'_> {
|
||||||
}
|
}
|
||||||
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
|
ast::Expr::UnderscoreExpr(_) => self.alloc_expr(Expr::Underscore, syntax_ptr),
|
||||||
ast::Expr::AsmExpr(e) => {
|
ast::Expr::AsmExpr(e) => {
|
||||||
let expr = Expr::InlineAsm(InlineAsm { e: self.collect_expr_opt(e.expr()) });
|
let e = self.collect_expr_opt(e.expr());
|
||||||
self.alloc_expr(expr, syntax_ptr)
|
self.alloc_expr(Expr::InlineAsm(InlineAsm { e }), syntax_ptr)
|
||||||
}
|
}
|
||||||
ast::Expr::OffsetOfExpr(e) => {
|
ast::Expr::OffsetOfExpr(e) => {
|
||||||
let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
|
let container = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
|
||||||
let fields = e.fields().map(|it| it.as_name()).collect();
|
let fields = e.fields().map(|it| it.as_name()).collect();
|
||||||
self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
|
self.alloc_expr(Expr::OffsetOf(OffsetOf { container, fields }), syntax_ptr)
|
||||||
}
|
}
|
||||||
ast::Expr::FormatArgsExpr(_) => self.missing_expr(),
|
ast::Expr::FormatArgsExpr(f) => self.collect_format_args(f, syntax_ptr),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1557,6 +1566,401 @@ impl ExprCollector<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// endregion: labels
|
// endregion: labels
|
||||||
|
|
||||||
|
// region: format
|
||||||
|
fn expand_macros_to_string(&mut self, expr: ast::Expr) -> Option<(ast::String, bool)> {
|
||||||
|
let m = match expr {
|
||||||
|
ast::Expr::MacroExpr(m) => m,
|
||||||
|
ast::Expr::Literal(l) => {
|
||||||
|
return match l.kind() {
|
||||||
|
ast::LiteralKind::String(s) => Some((s, true)),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
let e = m.macro_call()?;
|
||||||
|
let macro_ptr = AstPtr::new(&e);
|
||||||
|
let (exp, _) = self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
|
||||||
|
expansion.and_then(|it| this.expand_macros_to_string(it))
|
||||||
|
})?;
|
||||||
|
Some((exp, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_format_args(
|
||||||
|
&mut self,
|
||||||
|
f: ast::FormatArgsExpr,
|
||||||
|
syntax_ptr: AstPtr<ast::Expr>,
|
||||||
|
) -> ExprId {
|
||||||
|
let mut args = FormatArgumentsCollector::new();
|
||||||
|
f.args().for_each(|arg| {
|
||||||
|
args.add(FormatArgument {
|
||||||
|
kind: match arg.name() {
|
||||||
|
Some(name) => FormatArgumentKind::Named(name.as_name()),
|
||||||
|
None => FormatArgumentKind::Normal,
|
||||||
|
},
|
||||||
|
expr: self.collect_expr_opt(arg.expr()),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let template = f.template();
|
||||||
|
let fmt_snippet = template.as_ref().map(ToString::to_string);
|
||||||
|
let fmt = match template.and_then(|it| self.expand_macros_to_string(it)) {
|
||||||
|
Some((s, is_direct_literal)) => {
|
||||||
|
format_args::parse(&s, fmt_snippet, args, is_direct_literal, |name| {
|
||||||
|
self.alloc_expr_desugared(Expr::Path(Path::from(name)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => FormatArgs { template: Default::default(), arguments: args.finish() },
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a list of all _unique_ (argument, format trait) combinations.
|
||||||
|
// E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
|
||||||
|
let mut argmap = FxIndexSet::default();
|
||||||
|
for piece in fmt.template.iter() {
|
||||||
|
let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
|
||||||
|
if let Ok(index) = placeholder.argument.index {
|
||||||
|
argmap.insert((index, ArgumentType::Format(placeholder.format_trait)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let lit_pieces =
|
||||||
|
fmt.template
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, piece)| {
|
||||||
|
match piece {
|
||||||
|
FormatArgsPiece::Literal(s) => Some(
|
||||||
|
self.alloc_expr_desugared(Expr::Literal(Literal::String(s.clone()))),
|
||||||
|
),
|
||||||
|
&FormatArgsPiece::Placeholder(_) => {
|
||||||
|
// Inject empty string before placeholders when not already preceded by a literal piece.
|
||||||
|
if i == 0
|
||||||
|
|| matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_))
|
||||||
|
{
|
||||||
|
Some(self.alloc_expr_desugared(Expr::Literal(Literal::String(
|
||||||
|
"".into(),
|
||||||
|
))))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let lit_pieces = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
|
||||||
|
elements: lit_pieces,
|
||||||
|
is_assignee_expr: false,
|
||||||
|
}));
|
||||||
|
let lit_pieces = self.alloc_expr_desugared(Expr::Ref {
|
||||||
|
expr: lit_pieces,
|
||||||
|
rawness: Rawness::Ref,
|
||||||
|
mutability: Mutability::Shared,
|
||||||
|
});
|
||||||
|
let format_options = {
|
||||||
|
// Generate:
|
||||||
|
// &[format_spec_0, format_spec_1, format_spec_2]
|
||||||
|
let elements = fmt
|
||||||
|
.template
|
||||||
|
.iter()
|
||||||
|
.filter_map(|piece| {
|
||||||
|
let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
|
||||||
|
Some(self.make_format_spec(placeholder, &mut argmap))
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
|
||||||
|
elements,
|
||||||
|
is_assignee_expr: false,
|
||||||
|
}));
|
||||||
|
self.alloc_expr_desugared(Expr::Ref {
|
||||||
|
expr: array,
|
||||||
|
rawness: Rawness::Ref,
|
||||||
|
mutability: Mutability::Shared,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let arguments = &*fmt.arguments.arguments;
|
||||||
|
|
||||||
|
let args = if arguments.is_empty() {
|
||||||
|
let expr = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
|
||||||
|
elements: Box::default(),
|
||||||
|
is_assignee_expr: false,
|
||||||
|
}));
|
||||||
|
self.alloc_expr_desugared(Expr::Ref {
|
||||||
|
expr,
|
||||||
|
rawness: Rawness::Ref,
|
||||||
|
mutability: Mutability::Shared,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Generate:
|
||||||
|
// &match (&arg0, &arg1, &…) {
|
||||||
|
// args => [
|
||||||
|
// <core::fmt::Argument>::new_display(args.0),
|
||||||
|
// <core::fmt::Argument>::new_lower_hex(args.1),
|
||||||
|
// <core::fmt::Argument>::new_debug(args.0),
|
||||||
|
// …
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
let args = argmap
|
||||||
|
.iter()
|
||||||
|
.map(|&(arg_index, ty)| {
|
||||||
|
let arg = self.alloc_expr_desugared(Expr::Ref {
|
||||||
|
expr: arguments[arg_index].expr,
|
||||||
|
rawness: Rawness::Ref,
|
||||||
|
mutability: Mutability::Shared,
|
||||||
|
});
|
||||||
|
self.make_argument(arg, ty)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let array = self.alloc_expr_desugared(Expr::Array(Array::ElementList {
|
||||||
|
elements: args,
|
||||||
|
is_assignee_expr: false,
|
||||||
|
}));
|
||||||
|
self.alloc_expr_desugared(Expr::Ref {
|
||||||
|
expr: array,
|
||||||
|
rawness: Rawness::Ref,
|
||||||
|
mutability: Mutability::Shared,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate:
|
||||||
|
// <core::fmt::Arguments>::new_v1_formatted(
|
||||||
|
// lit_pieces,
|
||||||
|
// args,
|
||||||
|
// format_options,
|
||||||
|
// unsafe { ::core::fmt::UnsafeArg::new() }
|
||||||
|
// )
|
||||||
|
|
||||||
|
let Some(new_v1_formatted) =
|
||||||
|
LangItem::FormatArguments.ty_rel_path(self.db, self.krate, name![new_v1_formatted])
|
||||||
|
else {
|
||||||
|
return self.missing_expr();
|
||||||
|
};
|
||||||
|
let Some(unsafe_arg_new) =
|
||||||
|
LangItem::FormatUnsafeArg.ty_rel_path(self.db, self.krate, name![new])
|
||||||
|
else {
|
||||||
|
return self.missing_expr();
|
||||||
|
};
|
||||||
|
let new_v1_formatted = self.alloc_expr_desugared(Expr::Path(new_v1_formatted));
|
||||||
|
|
||||||
|
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Path(unsafe_arg_new));
|
||||||
|
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Call {
|
||||||
|
callee: unsafe_arg_new,
|
||||||
|
args: Box::default(),
|
||||||
|
is_assignee_expr: false,
|
||||||
|
});
|
||||||
|
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
|
||||||
|
id: None,
|
||||||
|
statements: Box::default(),
|
||||||
|
tail: Some(unsafe_arg_new),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.alloc_expr(
|
||||||
|
Expr::Call {
|
||||||
|
callee: new_v1_formatted,
|
||||||
|
args: Box::new([lit_pieces, args, format_options, unsafe_arg_new]),
|
||||||
|
is_assignee_expr: false,
|
||||||
|
},
|
||||||
|
syntax_ptr,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a hir expression for a format_args placeholder specification.
|
||||||
|
///
|
||||||
|
/// Generates
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// <core::fmt::rt::Placeholder::new(
|
||||||
|
/// …usize, // position
|
||||||
|
/// '…', // fill
|
||||||
|
/// <core::fmt::rt::Alignment>::…, // alignment
|
||||||
|
/// …u32, // flags
|
||||||
|
/// <core::fmt::rt::Count::…>, // width
|
||||||
|
/// <core::fmt::rt::Count::…>, // precision
|
||||||
|
/// )
|
||||||
|
/// ```
|
||||||
|
fn make_format_spec(
|
||||||
|
&mut self,
|
||||||
|
placeholder: &FormatPlaceholder,
|
||||||
|
argmap: &mut FxIndexSet<(usize, ArgumentType)>,
|
||||||
|
) -> ExprId {
|
||||||
|
let position = match placeholder.argument.index {
|
||||||
|
Ok(arg_index) => {
|
||||||
|
let (i, _) =
|
||||||
|
argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
|
||||||
|
self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
|
||||||
|
i as u128,
|
||||||
|
Some(BuiltinUint::Usize),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
Err(_) => self.missing_expr(),
|
||||||
|
};
|
||||||
|
let &FormatOptions {
|
||||||
|
ref width,
|
||||||
|
ref precision,
|
||||||
|
alignment,
|
||||||
|
fill,
|
||||||
|
sign,
|
||||||
|
alternate,
|
||||||
|
zero_pad,
|
||||||
|
debug_hex,
|
||||||
|
} = &placeholder.format_options;
|
||||||
|
let fill = self.alloc_expr_desugared(Expr::Literal(Literal::Char(fill.unwrap_or(' '))));
|
||||||
|
|
||||||
|
let align = {
|
||||||
|
let align = LangItem::FormatAlignment.ty_rel_path(
|
||||||
|
self.db,
|
||||||
|
self.krate,
|
||||||
|
match alignment {
|
||||||
|
Some(FormatAlignment::Left) => name![Left],
|
||||||
|
Some(FormatAlignment::Right) => name![Right],
|
||||||
|
Some(FormatAlignment::Center) => name![Center],
|
||||||
|
None => name![Unknown],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
match align {
|
||||||
|
Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
|
||||||
|
None => self.missing_expr(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// This needs to match `Flag` in library/core/src/fmt/rt.rs.
|
||||||
|
let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
|
||||||
|
| ((sign == Some(FormatSign::Minus)) as u32) << 1
|
||||||
|
| (alternate as u32) << 2
|
||||||
|
| (zero_pad as u32) << 3
|
||||||
|
| ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4
|
||||||
|
| ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5;
|
||||||
|
let flags = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
|
||||||
|
flags as u128,
|
||||||
|
Some(BuiltinUint::U32),
|
||||||
|
)));
|
||||||
|
let precision = self.make_count(&precision, argmap);
|
||||||
|
let width = self.make_count(&width, argmap);
|
||||||
|
|
||||||
|
let format_placeholder_new = {
|
||||||
|
let format_placeholder_new =
|
||||||
|
LangItem::FormatPlaceholder.ty_rel_path(self.db, self.krate, name![new]);
|
||||||
|
match format_placeholder_new {
|
||||||
|
Some(path) => self.alloc_expr_desugared(Expr::Path(path)),
|
||||||
|
None => self.missing_expr(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.alloc_expr_desugared(Expr::Call {
|
||||||
|
callee: format_placeholder_new,
|
||||||
|
args: Box::new([position, fill, align, flags, precision, width]),
|
||||||
|
is_assignee_expr: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a hir expression for a format_args Count.
|
||||||
|
///
|
||||||
|
/// Generates:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// <core::fmt::rt::Count>::Is(…)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// or
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// <core::fmt::rt::Count>::Param(…)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// or
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// <core::fmt::rt::Count>::Implied
|
||||||
|
/// ```
|
||||||
|
fn make_count(
|
||||||
|
&mut self,
|
||||||
|
count: &Option<FormatCount>,
|
||||||
|
argmap: &mut FxIndexSet<(usize, ArgumentType)>,
|
||||||
|
) -> ExprId {
|
||||||
|
match count {
|
||||||
|
Some(FormatCount::Literal(n)) => {
|
||||||
|
match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) {
|
||||||
|
Some(count_is) => {
|
||||||
|
let count_is = self.alloc_expr_desugared(Expr::Path(count_is));
|
||||||
|
let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
|
||||||
|
*n as u128,
|
||||||
|
Some(BuiltinUint::Usize),
|
||||||
|
)));
|
||||||
|
self.alloc_expr_desugared(Expr::Call {
|
||||||
|
callee: count_is,
|
||||||
|
args: Box::new([args]),
|
||||||
|
is_assignee_expr: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => self.missing_expr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(FormatCount::Argument(arg)) => {
|
||||||
|
if let Ok(arg_index) = arg.index {
|
||||||
|
let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
|
||||||
|
|
||||||
|
match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Param]) {
|
||||||
|
Some(count_param) => {
|
||||||
|
let count_param = self.alloc_expr_desugared(Expr::Path(count_param));
|
||||||
|
let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
|
||||||
|
i as u128,
|
||||||
|
Some(BuiltinUint::Usize),
|
||||||
|
)));
|
||||||
|
self.alloc_expr_desugared(Expr::Call {
|
||||||
|
callee: count_param,
|
||||||
|
args: Box::new([args]),
|
||||||
|
is_assignee_expr: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => self.missing_expr(),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.missing_expr()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Implied]) {
|
||||||
|
Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
|
||||||
|
None => self.missing_expr(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a hir expression representing an argument to a format_args invocation.
|
||||||
|
///
|
||||||
|
/// Generates:
|
||||||
|
///
|
||||||
|
/// ```text
|
||||||
|
/// <core::fmt::Argument>::new_…(arg)
|
||||||
|
/// ```
|
||||||
|
fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
|
||||||
|
use ArgumentType::*;
|
||||||
|
use FormatTrait::*;
|
||||||
|
match LangItem::FormatArgument.ty_rel_path(
|
||||||
|
self.db,
|
||||||
|
self.krate,
|
||||||
|
match ty {
|
||||||
|
Format(Display) => name![new_display],
|
||||||
|
Format(Debug) => name![new_debug],
|
||||||
|
Format(LowerExp) => name![new_lower_exp],
|
||||||
|
Format(UpperExp) => name![new_upper_exp],
|
||||||
|
Format(Octal) => name![new_octal],
|
||||||
|
Format(Pointer) => name![new_pointer],
|
||||||
|
Format(Binary) => name![new_binary],
|
||||||
|
Format(LowerHex) => name![new_lower_hex],
|
||||||
|
Format(UpperHex) => name![new_upper_hex],
|
||||||
|
Usize => name![from_usize],
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Some(new_fn) => {
|
||||||
|
let new_fn = self.alloc_expr_desugared(Expr::Path(new_fn));
|
||||||
|
self.alloc_expr_desugared(Expr::Call {
|
||||||
|
callee: new_fn,
|
||||||
|
args: Box::new([arg]),
|
||||||
|
is_assignee_expr: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => self.missing_expr(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion: format
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
|
fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> {
|
||||||
|
@ -1632,3 +2036,9 @@ fn comma_follows_token(t: Option<syntax::SyntaxToken>) -> bool {
|
||||||
(|| syntax::algo::skip_trivia_token(t?.next_token()?, syntax::Direction::Next))()
|
(|| syntax::algo::skip_trivia_token(t?.next_token()?, syntax::Direction::Next))()
|
||||||
.map_or(false, |it| it.kind() == syntax::T![,])
|
.map_or(false, |it| it.kind() == syntax::T![,])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
|
enum ArgumentType {
|
||||||
|
Format(FormatTrait),
|
||||||
|
Usize,
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
use hir_expand::db::ExpandDatabase;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use syntax::ast::HasName;
|
use syntax::ast::HasName;
|
||||||
|
|
||||||
|
@ -52,8 +51,7 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut p =
|
let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false };
|
||||||
Printer { db: db.upcast(), body, buf: header, indent_level: 0, needs_indent: false };
|
|
||||||
if let DefWithBodyId::FunctionId(it) = owner {
|
if let DefWithBodyId::FunctionId(it) = owner {
|
||||||
p.buf.push('(');
|
p.buf.push('(');
|
||||||
body.params.iter().zip(&db.function_data(it).params).for_each(|(¶m, ty)| {
|
body.params.iter().zip(&db.function_data(it).params).for_each(|(¶m, ty)| {
|
||||||
|
@ -77,8 +75,7 @@ pub(super) fn print_expr_hir(
|
||||||
_owner: DefWithBodyId,
|
_owner: DefWithBodyId,
|
||||||
expr: ExprId,
|
expr: ExprId,
|
||||||
) -> String {
|
) -> String {
|
||||||
let mut p =
|
let mut p = Printer { db, body, buf: String::new(), indent_level: 0, needs_indent: false };
|
||||||
Printer { db: db.upcast(), body, buf: String::new(), indent_level: 0, needs_indent: false };
|
|
||||||
p.print_expr(expr);
|
p.print_expr(expr);
|
||||||
p.buf
|
p.buf
|
||||||
}
|
}
|
||||||
|
@ -99,7 +96,7 @@ macro_rules! wln {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Printer<'a> {
|
struct Printer<'a> {
|
||||||
db: &'a dyn ExpandDatabase,
|
db: &'a dyn DefDatabase,
|
||||||
body: &'a Body,
|
body: &'a Body,
|
||||||
buf: String,
|
buf: String,
|
||||||
indent_level: usize,
|
indent_level: usize,
|
||||||
|
@ -143,9 +140,14 @@ impl Printer<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn newline(&mut self) {
|
fn newline(&mut self) {
|
||||||
match self.buf.chars().rev().find(|ch| *ch != ' ') {
|
match self.buf.chars().rev().find_position(|ch| *ch != ' ') {
|
||||||
Some('\n') | None => {}
|
Some((_, '\n')) | None => {}
|
||||||
_ => writeln!(self).unwrap(),
|
Some((idx, _)) => {
|
||||||
|
if idx != 0 {
|
||||||
|
self.buf.drain(self.buf.len() - idx..);
|
||||||
|
}
|
||||||
|
writeln!(self).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +164,10 @@ impl Printer<'_> {
|
||||||
w!(
|
w!(
|
||||||
self,
|
self,
|
||||||
", {})",
|
", {})",
|
||||||
offset_of.fields.iter().format_with(".", |field, f| f(&field.display(self.db)))
|
offset_of
|
||||||
|
.fields
|
||||||
|
.iter()
|
||||||
|
.format_with(".", |field, f| f(&field.display(self.db.upcast())))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Expr::Path(path) => self.print_path(path),
|
Expr::Path(path) => self.print_path(path),
|
||||||
|
@ -184,7 +189,7 @@ impl Printer<'_> {
|
||||||
}
|
}
|
||||||
Expr::Loop { body, label } => {
|
Expr::Loop { body, label } => {
|
||||||
if let Some(lbl) = label {
|
if let Some(lbl) = label {
|
||||||
w!(self, "{}: ", self.body[*lbl].name.display(self.db));
|
w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
w!(self, "loop ");
|
w!(self, "loop ");
|
||||||
self.print_expr(*body);
|
self.print_expr(*body);
|
||||||
|
@ -204,7 +209,7 @@ impl Printer<'_> {
|
||||||
}
|
}
|
||||||
Expr::MethodCall { receiver, method_name, args, generic_args } => {
|
Expr::MethodCall { receiver, method_name, args, generic_args } => {
|
||||||
self.print_expr(*receiver);
|
self.print_expr(*receiver);
|
||||||
w!(self, ".{}", method_name.display(self.db));
|
w!(self, ".{}", method_name.display(self.db.upcast()));
|
||||||
if let Some(args) = generic_args {
|
if let Some(args) = generic_args {
|
||||||
w!(self, "::<");
|
w!(self, "::<");
|
||||||
print_generic_args(self.db, args, self).unwrap();
|
print_generic_args(self.db, args, self).unwrap();
|
||||||
|
@ -242,13 +247,13 @@ impl Printer<'_> {
|
||||||
Expr::Continue { label } => {
|
Expr::Continue { label } => {
|
||||||
w!(self, "continue");
|
w!(self, "continue");
|
||||||
if let Some(lbl) = label {
|
if let Some(lbl) = label {
|
||||||
w!(self, " {}", self.body[*lbl].name.display(self.db));
|
w!(self, " {}", self.body[*lbl].name.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Break { expr, label } => {
|
Expr::Break { expr, label } => {
|
||||||
w!(self, "break");
|
w!(self, "break");
|
||||||
if let Some(lbl) = label {
|
if let Some(lbl) = label {
|
||||||
w!(self, " {}", self.body[*lbl].name.display(self.db));
|
w!(self, " {}", self.body[*lbl].name.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
self.whitespace();
|
self.whitespace();
|
||||||
|
@ -287,7 +292,7 @@ impl Printer<'_> {
|
||||||
w!(self, "{{");
|
w!(self, "{{");
|
||||||
self.indented(|p| {
|
self.indented(|p| {
|
||||||
for field in &**fields {
|
for field in &**fields {
|
||||||
w!(p, "{}: ", field.name.display(self.db));
|
w!(p, "{}: ", field.name.display(self.db.upcast()));
|
||||||
p.print_expr(field.expr);
|
p.print_expr(field.expr);
|
||||||
wln!(p, ",");
|
wln!(p, ",");
|
||||||
}
|
}
|
||||||
|
@ -304,7 +309,7 @@ impl Printer<'_> {
|
||||||
}
|
}
|
||||||
Expr::Field { expr, name } => {
|
Expr::Field { expr, name } => {
|
||||||
self.print_expr(*expr);
|
self.print_expr(*expr);
|
||||||
w!(self, ".{}", name.display(self.db));
|
w!(self, ".{}", name.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
Expr::Await { expr } => {
|
Expr::Await { expr } => {
|
||||||
self.print_expr(*expr);
|
self.print_expr(*expr);
|
||||||
|
@ -442,7 +447,8 @@ impl Printer<'_> {
|
||||||
}
|
}
|
||||||
Expr::Literal(lit) => self.print_literal(lit),
|
Expr::Literal(lit) => self.print_literal(lit),
|
||||||
Expr::Block { id: _, statements, tail, label } => {
|
Expr::Block { id: _, statements, tail, label } => {
|
||||||
let label = label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db)));
|
let label =
|
||||||
|
label.map(|lbl| format!("{}: ", self.body[lbl].name.display(self.db.upcast())));
|
||||||
self.print_block(label.as_deref(), statements, tail);
|
self.print_block(label.as_deref(), statements, tail);
|
||||||
}
|
}
|
||||||
Expr::Unsafe { id: _, statements, tail } => {
|
Expr::Unsafe { id: _, statements, tail } => {
|
||||||
|
@ -518,7 +524,7 @@ impl Printer<'_> {
|
||||||
w!(self, " {{");
|
w!(self, " {{");
|
||||||
self.indented(|p| {
|
self.indented(|p| {
|
||||||
for arg in args.iter() {
|
for arg in args.iter() {
|
||||||
w!(p, "{}: ", arg.name.display(self.db));
|
w!(p, "{}: ", arg.name.display(self.db.upcast()));
|
||||||
p.print_pat(arg.pat);
|
p.print_pat(arg.pat);
|
||||||
wln!(p, ",");
|
wln!(p, ",");
|
||||||
}
|
}
|
||||||
|
@ -677,6 +683,6 @@ impl Printer<'_> {
|
||||||
BindingAnnotation::Ref => "ref ",
|
BindingAnnotation::Ref => "ref ",
|
||||||
BindingAnnotation::RefMut => "ref mut ",
|
BindingAnnotation::RefMut => "ref mut ",
|
||||||
};
|
};
|
||||||
w!(self, "{}{}", mode, name.display(self.db));
|
w!(self, "{}{}", mode, name.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
mod block;
|
mod block;
|
||||||
|
|
||||||
use base_db::{fixture::WithFixture, SourceDatabase};
|
use base_db::{fixture::WithFixture, SourceDatabase};
|
||||||
use expect_test::Expect;
|
use expect_test::{expect, Expect};
|
||||||
|
|
||||||
use crate::{test_db::TestDB, ModuleDefId};
|
use crate::{test_db::TestDB, ModuleDefId};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn lower(ra_fixture: &str) -> Arc<Body> {
|
fn lower(ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
|
||||||
let db = TestDB::with_files(ra_fixture);
|
let db = TestDB::with_files(ra_fixture);
|
||||||
|
|
||||||
let krate = db.crate_graph().iter().next().unwrap();
|
let krate = db.crate_graph().iter().next().unwrap();
|
||||||
|
@ -21,8 +21,10 @@ fn lower(ra_fixture: &str) -> Arc<Body> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let fn_def = fn_def.unwrap().into();
|
||||||
|
|
||||||
db.body(fn_def.unwrap().into())
|
let body = db.body(fn_def);
|
||||||
|
(db, body, fn_def)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn def_map_at(ra_fixture: &str) -> String {
|
fn def_map_at(ra_fixture: &str) -> String {
|
||||||
|
@ -138,3 +140,84 @@ mod m {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn desugar_builtin_format_args() {
|
||||||
|
// Regression test for a path resolution bug introduced with inner item handling.
|
||||||
|
let (db, body, def) = lower(
|
||||||
|
r#"
|
||||||
|
//- minicore: fmt
|
||||||
|
fn main() {
|
||||||
|
let are = "are";
|
||||||
|
let count = 10;
|
||||||
|
builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect![[r#"
|
||||||
|
fn main() {
|
||||||
|
let are = "are";
|
||||||
|
let count = 10;
|
||||||
|
builtin#lang(Arguments::new_v1_formatted)(
|
||||||
|
&[
|
||||||
|
"\"hello ", " ", " friends, we ", " ", "", "\"",
|
||||||
|
],
|
||||||
|
&[
|
||||||
|
builtin#lang(Argument::new_display)(
|
||||||
|
&count,
|
||||||
|
), builtin#lang(Argument::new_display)(
|
||||||
|
&"fancy",
|
||||||
|
), builtin#lang(Argument::new_debug)(
|
||||||
|
&are,
|
||||||
|
), builtin#lang(Argument::new_display)(
|
||||||
|
&"!",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
&[
|
||||||
|
builtin#lang(Placeholder::new)(
|
||||||
|
0usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
8u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Is)(
|
||||||
|
2usize,
|
||||||
|
),
|
||||||
|
), builtin#lang(Placeholder::new)(
|
||||||
|
1usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
0u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
), builtin#lang(Placeholder::new)(
|
||||||
|
2usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
0u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
), builtin#lang(Placeholder::new)(
|
||||||
|
1usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
0u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
), builtin#lang(Placeholder::new)(
|
||||||
|
3usize,
|
||||||
|
' ',
|
||||||
|
builtin#lang(Alignment::Unknown),
|
||||||
|
0u32,
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
builtin#lang(Count::Implied),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
unsafe {
|
||||||
|
builtin#lang(UnsafeArg::new)()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}"#]]
|
||||||
|
.assert_eq(&body.pretty_print(&db, def))
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
//! See also a neighboring `body` module.
|
//! See also a neighboring `body` module.
|
||||||
|
|
||||||
pub mod type_ref;
|
pub mod type_ref;
|
||||||
|
pub mod format_args;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
@ -117,7 +118,6 @@ impl From<ast::LiteralKind> for Literal {
|
||||||
fn from(ast_lit_kind: ast::LiteralKind) -> Self {
|
fn from(ast_lit_kind: ast::LiteralKind) -> Self {
|
||||||
use ast::LiteralKind;
|
use ast::LiteralKind;
|
||||||
match ast_lit_kind {
|
match ast_lit_kind {
|
||||||
// FIXME: these should have actual values filled in, but unsure on perf impact
|
|
||||||
LiteralKind::IntNumber(lit) => {
|
LiteralKind::IntNumber(lit) => {
|
||||||
if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
|
if let builtin @ Some(_) = lit.suffix().and_then(BuiltinFloat::from_suffix) {
|
||||||
Literal::Float(
|
Literal::Float(
|
||||||
|
@ -355,7 +355,7 @@ impl Expr {
|
||||||
match self {
|
match self {
|
||||||
Expr::Missing => {}
|
Expr::Missing => {}
|
||||||
Expr::Path(_) | Expr::OffsetOf(_) => {}
|
Expr::Path(_) | Expr::OffsetOf(_) => {}
|
||||||
Expr::InlineAsm(e) => f(e.e),
|
Expr::InlineAsm(it) => f(it.e),
|
||||||
Expr::If { condition, then_branch, else_branch } => {
|
Expr::If { condition, then_branch, else_branch } => {
|
||||||
f(*condition);
|
f(*condition);
|
||||||
f(*then_branch);
|
f(*then_branch);
|
||||||
|
|
503
crates/hir-def/src/hir/format_args.rs
Normal file
503
crates/hir-def/src/hir/format_args.rs
Normal file
|
@ -0,0 +1,503 @@
|
||||||
|
//! Parses `format_args` input.
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
use hir_expand::name::Name;
|
||||||
|
use syntax::{
|
||||||
|
ast::{self, IsString},
|
||||||
|
AstToken, SmolStr, TextRange,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::hir::ExprId;
|
||||||
|
|
||||||
|
mod parse;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct FormatArgs {
|
||||||
|
pub template: Box<[FormatArgsPiece]>,
|
||||||
|
pub arguments: FormatArguments,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct FormatArguments {
|
||||||
|
pub arguments: Box<[FormatArgument]>,
|
||||||
|
pub num_unnamed_args: usize,
|
||||||
|
pub num_explicit_args: usize,
|
||||||
|
pub names: Box<[(Name, usize)]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum FormatArgsPiece {
|
||||||
|
Literal(Box<str>),
|
||||||
|
Placeholder(FormatPlaceholder),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct FormatPlaceholder {
|
||||||
|
/// Index into [`FormatArgs::arguments`].
|
||||||
|
pub argument: FormatArgPosition,
|
||||||
|
/// The span inside the format string for the full `{…}` placeholder.
|
||||||
|
pub span: Option<TextRange>,
|
||||||
|
/// `{}`, `{:?}`, or `{:x}`, etc.
|
||||||
|
pub format_trait: FormatTrait,
|
||||||
|
/// `{}` or `{:.5}` or `{:-^20}`, etc.
|
||||||
|
pub format_options: FormatOptions,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct FormatArgPosition {
|
||||||
|
/// Which argument this position refers to (Ok),
|
||||||
|
/// or would've referred to if it existed (Err).
|
||||||
|
pub index: Result<usize, usize>,
|
||||||
|
/// What kind of position this is. See [`FormatArgPositionKind`].
|
||||||
|
pub kind: FormatArgPositionKind,
|
||||||
|
/// The span of the name or number.
|
||||||
|
pub span: Option<TextRange>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum FormatArgPositionKind {
|
||||||
|
/// `{}` or `{:.*}`
|
||||||
|
Implicit,
|
||||||
|
/// `{1}` or `{:1$}` or `{:.1$}`
|
||||||
|
Number,
|
||||||
|
/// `{a}` or `{:a$}` or `{:.a$}`
|
||||||
|
Named,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub enum FormatTrait {
|
||||||
|
/// `{}`
|
||||||
|
Display,
|
||||||
|
/// `{:?}`
|
||||||
|
Debug,
|
||||||
|
/// `{:e}`
|
||||||
|
LowerExp,
|
||||||
|
/// `{:E}`
|
||||||
|
UpperExp,
|
||||||
|
/// `{:o}`
|
||||||
|
Octal,
|
||||||
|
/// `{:p}`
|
||||||
|
Pointer,
|
||||||
|
/// `{:b}`
|
||||||
|
Binary,
|
||||||
|
/// `{:x}`
|
||||||
|
LowerHex,
|
||||||
|
/// `{:X}`
|
||||||
|
UpperHex,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
|
||||||
|
pub struct FormatOptions {
|
||||||
|
/// The width. E.g. `{:5}` or `{:width$}`.
|
||||||
|
pub width: Option<FormatCount>,
|
||||||
|
/// The precision. E.g. `{:.5}` or `{:.precision$}`.
|
||||||
|
pub precision: Option<FormatCount>,
|
||||||
|
/// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
|
||||||
|
pub alignment: Option<FormatAlignment>,
|
||||||
|
/// The fill character. E.g. the `.` in `{:.>10}`.
|
||||||
|
pub fill: Option<char>,
|
||||||
|
/// The `+` or `-` flag.
|
||||||
|
pub sign: Option<FormatSign>,
|
||||||
|
/// The `#` flag.
|
||||||
|
pub alternate: bool,
|
||||||
|
/// The `0` flag. E.g. the `0` in `{:02x}`.
|
||||||
|
pub zero_pad: bool,
|
||||||
|
/// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`.
|
||||||
|
pub debug_hex: Option<FormatDebugHex>,
|
||||||
|
}
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum FormatSign {
|
||||||
|
/// The `+` flag.
|
||||||
|
Plus,
|
||||||
|
/// The `-` flag.
|
||||||
|
Minus,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum FormatDebugHex {
|
||||||
|
/// The `x` flag in `{:x?}`.
|
||||||
|
Lower,
|
||||||
|
/// The `X` flag in `{:X?}`.
|
||||||
|
Upper,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum FormatAlignment {
|
||||||
|
/// `{:<}`
|
||||||
|
Left,
|
||||||
|
/// `{:>}`
|
||||||
|
Right,
|
||||||
|
/// `{:^}`
|
||||||
|
Center,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum FormatCount {
|
||||||
|
/// `{:5}` or `{:.5}`
|
||||||
|
Literal(usize),
|
||||||
|
/// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
|
||||||
|
Argument(FormatArgPosition),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct FormatArgument {
|
||||||
|
pub kind: FormatArgumentKind,
|
||||||
|
pub expr: ExprId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum FormatArgumentKind {
|
||||||
|
/// `format_args(…, arg)`
|
||||||
|
Normal,
|
||||||
|
/// `format_args(…, arg = 1)`
|
||||||
|
Named(Name),
|
||||||
|
/// `format_args("… {arg} …")`
|
||||||
|
Captured(Name),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only used in parse_args and report_invalid_references,
|
||||||
|
// to indicate how a referred argument was used.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
|
enum PositionUsedAs {
|
||||||
|
Placeholder(Option<TextRange>),
|
||||||
|
Precision,
|
||||||
|
Width,
|
||||||
|
}
|
||||||
|
use PositionUsedAs::*;
|
||||||
|
|
||||||
|
pub(crate) fn parse(
|
||||||
|
s: &ast::String,
|
||||||
|
fmt_snippet: Option<String>,
|
||||||
|
mut args: FormatArgumentsCollector,
|
||||||
|
is_direct_literal: bool,
|
||||||
|
mut synth: impl FnMut(Name) -> ExprId,
|
||||||
|
) -> FormatArgs {
|
||||||
|
let text = s.text();
|
||||||
|
let str_style = match s.quote_offsets() {
|
||||||
|
Some(offsets) => {
|
||||||
|
let raw = u32::from(offsets.quotes.0.len()) - 1;
|
||||||
|
(raw != 0).then_some(raw as usize)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let mut parser =
|
||||||
|
parse::Parser::new(text, str_style, fmt_snippet, false, parse::ParseMode::Format);
|
||||||
|
|
||||||
|
let mut pieces = Vec::new();
|
||||||
|
while let Some(piece) = parser.next() {
|
||||||
|
if !parser.errors.is_empty() {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
pieces.push(piece);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let is_source_literal = parser.is_source_literal;
|
||||||
|
if !parser.errors.is_empty() {
|
||||||
|
// FIXME: Diagnose
|
||||||
|
return FormatArgs { template: Default::default(), arguments: args.finish() };
|
||||||
|
}
|
||||||
|
|
||||||
|
let to_span = |inner_span: parse::InnerSpan| {
|
||||||
|
is_source_literal.then(|| {
|
||||||
|
TextRange::new(inner_span.start.try_into().unwrap(), inner_span.end.try_into().unwrap())
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut used = vec![false; args.explicit_args().len()];
|
||||||
|
let mut invalid_refs = Vec::new();
|
||||||
|
let mut numeric_refences_to_named_arg = Vec::new();
|
||||||
|
|
||||||
|
enum ArgRef<'a> {
|
||||||
|
Index(usize),
|
||||||
|
Name(&'a str, Option<TextRange>),
|
||||||
|
}
|
||||||
|
let mut lookup_arg = |arg: ArgRef<'_>,
|
||||||
|
span: Option<TextRange>,
|
||||||
|
used_as: PositionUsedAs,
|
||||||
|
kind: FormatArgPositionKind|
|
||||||
|
-> FormatArgPosition {
|
||||||
|
let index = match arg {
|
||||||
|
ArgRef::Index(index) => {
|
||||||
|
if let Some(arg) = args.by_index(index) {
|
||||||
|
used[index] = true;
|
||||||
|
if arg.kind.ident().is_some() {
|
||||||
|
// This was a named argument, but it was used as a positional argument.
|
||||||
|
numeric_refences_to_named_arg.push((index, span, used_as));
|
||||||
|
}
|
||||||
|
Ok(index)
|
||||||
|
} else {
|
||||||
|
// Doesn't exist as an explicit argument.
|
||||||
|
invalid_refs.push((index, span, used_as, kind));
|
||||||
|
Err(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ArgRef::Name(name, _span) => {
|
||||||
|
let name = Name::new_text_dont_use(SmolStr::new(name));
|
||||||
|
if let Some((index, _)) = args.by_name(&name) {
|
||||||
|
// Name found in `args`, so we resolve it to its index.
|
||||||
|
if index < args.explicit_args().len() {
|
||||||
|
// Mark it as used, if it was an explicit argument.
|
||||||
|
used[index] = true;
|
||||||
|
}
|
||||||
|
Ok(index)
|
||||||
|
} else {
|
||||||
|
// Name not found in `args`, so we add it as an implicitly captured argument.
|
||||||
|
if !is_direct_literal {
|
||||||
|
// For the moment capturing variables from format strings expanded from macros is
|
||||||
|
// disabled (see RFC #2795)
|
||||||
|
// FIXME: Diagnose
|
||||||
|
}
|
||||||
|
Ok(args.add(FormatArgument {
|
||||||
|
kind: FormatArgumentKind::Captured(name.clone()),
|
||||||
|
// FIXME: This is problematic, we might want to synthesize a dummy
|
||||||
|
// expression proper and/or desugar these.
|
||||||
|
expr: synth(name),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FormatArgPosition { index, kind, span }
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut template = Vec::new();
|
||||||
|
let mut unfinished_literal = String::new();
|
||||||
|
let mut placeholder_index = 0;
|
||||||
|
|
||||||
|
for piece in pieces {
|
||||||
|
match piece {
|
||||||
|
parse::Piece::String(s) => {
|
||||||
|
unfinished_literal.push_str(s);
|
||||||
|
}
|
||||||
|
parse::Piece::NextArgument(arg) => {
|
||||||
|
let parse::Argument { position, position_span, format } = *arg;
|
||||||
|
if !unfinished_literal.is_empty() {
|
||||||
|
template.push(FormatArgsPiece::Literal(
|
||||||
|
mem::take(&mut unfinished_literal).into_boxed_str(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s));
|
||||||
|
placeholder_index += 1;
|
||||||
|
|
||||||
|
let position_span = to_span(position_span);
|
||||||
|
let argument = match position {
|
||||||
|
parse::ArgumentImplicitlyIs(i) => lookup_arg(
|
||||||
|
ArgRef::Index(i),
|
||||||
|
position_span,
|
||||||
|
Placeholder(span),
|
||||||
|
FormatArgPositionKind::Implicit,
|
||||||
|
),
|
||||||
|
parse::ArgumentIs(i) => lookup_arg(
|
||||||
|
ArgRef::Index(i),
|
||||||
|
position_span,
|
||||||
|
Placeholder(span),
|
||||||
|
FormatArgPositionKind::Number,
|
||||||
|
),
|
||||||
|
parse::ArgumentNamed(name) => lookup_arg(
|
||||||
|
ArgRef::Name(name, position_span),
|
||||||
|
position_span,
|
||||||
|
Placeholder(span),
|
||||||
|
FormatArgPositionKind::Named,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let alignment = match format.align {
|
||||||
|
parse::AlignUnknown => None,
|
||||||
|
parse::AlignLeft => Some(FormatAlignment::Left),
|
||||||
|
parse::AlignRight => Some(FormatAlignment::Right),
|
||||||
|
parse::AlignCenter => Some(FormatAlignment::Center),
|
||||||
|
};
|
||||||
|
|
||||||
|
let format_trait = match format.ty {
|
||||||
|
"" => FormatTrait::Display,
|
||||||
|
"?" => FormatTrait::Debug,
|
||||||
|
"e" => FormatTrait::LowerExp,
|
||||||
|
"E" => FormatTrait::UpperExp,
|
||||||
|
"o" => FormatTrait::Octal,
|
||||||
|
"p" => FormatTrait::Pointer,
|
||||||
|
"b" => FormatTrait::Binary,
|
||||||
|
"x" => FormatTrait::LowerHex,
|
||||||
|
"X" => FormatTrait::UpperHex,
|
||||||
|
_ => {
|
||||||
|
// FIXME: Diagnose
|
||||||
|
FormatTrait::Display
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let precision_span = format.precision_span.and_then(to_span);
|
||||||
|
let precision = match format.precision {
|
||||||
|
parse::CountIs(n) => Some(FormatCount::Literal(n)),
|
||||||
|
parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
|
||||||
|
ArgRef::Name(name, to_span(name_span)),
|
||||||
|
precision_span,
|
||||||
|
Precision,
|
||||||
|
FormatArgPositionKind::Named,
|
||||||
|
))),
|
||||||
|
parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
|
||||||
|
ArgRef::Index(i),
|
||||||
|
precision_span,
|
||||||
|
Precision,
|
||||||
|
FormatArgPositionKind::Number,
|
||||||
|
))),
|
||||||
|
parse::CountIsStar(i) => Some(FormatCount::Argument(lookup_arg(
|
||||||
|
ArgRef::Index(i),
|
||||||
|
precision_span,
|
||||||
|
Precision,
|
||||||
|
FormatArgPositionKind::Implicit,
|
||||||
|
))),
|
||||||
|
parse::CountImplied => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let width_span = format.width_span.and_then(to_span);
|
||||||
|
let width = match format.width {
|
||||||
|
parse::CountIs(n) => Some(FormatCount::Literal(n)),
|
||||||
|
parse::CountIsName(name, name_span) => Some(FormatCount::Argument(lookup_arg(
|
||||||
|
ArgRef::Name(name, to_span(name_span)),
|
||||||
|
width_span,
|
||||||
|
Width,
|
||||||
|
FormatArgPositionKind::Named,
|
||||||
|
))),
|
||||||
|
parse::CountIsParam(i) => Some(FormatCount::Argument(lookup_arg(
|
||||||
|
ArgRef::Index(i),
|
||||||
|
width_span,
|
||||||
|
Width,
|
||||||
|
FormatArgPositionKind::Number,
|
||||||
|
))),
|
||||||
|
parse::CountIsStar(_) => unreachable!(),
|
||||||
|
parse::CountImplied => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
template.push(FormatArgsPiece::Placeholder(FormatPlaceholder {
|
||||||
|
argument,
|
||||||
|
span,
|
||||||
|
format_trait,
|
||||||
|
format_options: FormatOptions {
|
||||||
|
fill: format.fill,
|
||||||
|
alignment,
|
||||||
|
sign: format.sign.map(|s| match s {
|
||||||
|
parse::Sign::Plus => FormatSign::Plus,
|
||||||
|
parse::Sign::Minus => FormatSign::Minus,
|
||||||
|
}),
|
||||||
|
alternate: format.alternate,
|
||||||
|
zero_pad: format.zero_pad,
|
||||||
|
debug_hex: format.debug_hex.map(|s| match s {
|
||||||
|
parse::DebugHex::Lower => FormatDebugHex::Lower,
|
||||||
|
parse::DebugHex::Upper => FormatDebugHex::Upper,
|
||||||
|
}),
|
||||||
|
precision,
|
||||||
|
width,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !unfinished_literal.is_empty() {
|
||||||
|
template.push(FormatArgsPiece::Literal(unfinished_literal.into_boxed_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !invalid_refs.is_empty() {
|
||||||
|
// FIXME: Diagnose
|
||||||
|
}
|
||||||
|
|
||||||
|
let unused = used
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter(|&(_, used)| !used)
|
||||||
|
.map(|(i, _)| {
|
||||||
|
let named = matches!(args.explicit_args()[i].kind, FormatArgumentKind::Named(_));
|
||||||
|
(args.explicit_args()[i].expr, named)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
if !unused.is_empty() {
|
||||||
|
// FIXME: Diagnose
|
||||||
|
}
|
||||||
|
|
||||||
|
FormatArgs { template: template.into_boxed_slice(), arguments: args.finish() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct FormatArgumentsCollector {
|
||||||
|
arguments: Vec<FormatArgument>,
|
||||||
|
num_unnamed_args: usize,
|
||||||
|
num_explicit_args: usize,
|
||||||
|
names: Vec<(Name, usize)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormatArgumentsCollector {
|
||||||
|
pub(crate) fn finish(self) -> FormatArguments {
|
||||||
|
FormatArguments {
|
||||||
|
arguments: self.arguments.into_boxed_slice(),
|
||||||
|
num_unnamed_args: self.num_unnamed_args,
|
||||||
|
num_explicit_args: self.num_explicit_args,
|
||||||
|
names: self.names.into_boxed_slice(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self { arguments: vec![], names: vec![], num_unnamed_args: 0, num_explicit_args: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&mut self, arg: FormatArgument) -> usize {
|
||||||
|
let index = self.arguments.len();
|
||||||
|
if let Some(name) = arg.kind.ident() {
|
||||||
|
self.names.push((name.clone(), index));
|
||||||
|
} else if self.names.is_empty() {
|
||||||
|
// Only count the unnamed args before the first named arg.
|
||||||
|
// (Any later ones are errors.)
|
||||||
|
self.num_unnamed_args += 1;
|
||||||
|
}
|
||||||
|
if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
|
||||||
|
// This is an explicit argument.
|
||||||
|
// Make sure that all arguments so far are explicit.
|
||||||
|
assert_eq!(
|
||||||
|
self.num_explicit_args,
|
||||||
|
self.arguments.len(),
|
||||||
|
"captured arguments must be added last"
|
||||||
|
);
|
||||||
|
self.num_explicit_args += 1;
|
||||||
|
}
|
||||||
|
self.arguments.push(arg);
|
||||||
|
index
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn by_name(&self, name: &Name) -> Option<(usize, &FormatArgument)> {
|
||||||
|
let &(_, i) = self.names.iter().find(|(n, _)| n == name)?;
|
||||||
|
Some((i, &self.arguments[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
|
||||||
|
(i < self.num_explicit_args).then(|| &self.arguments[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unnamed_args(&self) -> &[FormatArgument] {
|
||||||
|
&self.arguments[..self.num_unnamed_args]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn named_args(&self) -> &[FormatArgument] {
|
||||||
|
&self.arguments[self.num_unnamed_args..self.num_explicit_args]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn explicit_args(&self) -> &[FormatArgument] {
|
||||||
|
&self.arguments[..self.num_explicit_args]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn all_args(&self) -> &[FormatArgument] {
|
||||||
|
&self.arguments[..]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn all_args_mut(&mut self) -> &mut Vec<FormatArgument> {
|
||||||
|
&mut self.arguments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FormatArgumentKind {
|
||||||
|
pub fn ident(&self) -> Option<&Name> {
|
||||||
|
match self {
|
||||||
|
Self::Normal => None,
|
||||||
|
Self::Named(id) => Some(id),
|
||||||
|
Self::Captured(id) => Some(id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1023
crates/hir-def/src/hir/format_args/parse.rs
Normal file
1023
crates/hir-def/src/hir/format_args/parse.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -177,7 +177,7 @@ impl ItemTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pretty_print(&self, db: &dyn DefDatabase) -> String {
|
pub fn pretty_print(&self, db: &dyn DefDatabase) -> String {
|
||||||
pretty::print_item_tree(db.upcast(), self)
|
pretty::print_item_tree(db, self)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn data(&self) -> &ItemTreeData {
|
fn data(&self) -> &ItemTreeData {
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
use hir_expand::db::ExpandDatabase;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
|
generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
|
||||||
pretty::{print_path, print_type_bounds, print_type_ref},
|
pretty::{print_path, print_type_bounds, print_type_ref},
|
||||||
|
@ -12,7 +10,7 @@ use crate::{
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub(super) fn print_item_tree(db: &dyn ExpandDatabase, tree: &ItemTree) -> String {
|
pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree) -> String {
|
||||||
let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true };
|
let mut p = Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true };
|
||||||
|
|
||||||
if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
|
if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
|
||||||
|
@ -45,7 +43,7 @@ macro_rules! wln {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Printer<'a> {
|
struct Printer<'a> {
|
||||||
db: &'a dyn ExpandDatabase,
|
db: &'a dyn DefDatabase,
|
||||||
tree: &'a ItemTree,
|
tree: &'a ItemTree,
|
||||||
buf: String,
|
buf: String,
|
||||||
indent_level: usize,
|
indent_level: usize,
|
||||||
|
@ -91,7 +89,7 @@ impl Printer<'_> {
|
||||||
self,
|
self,
|
||||||
"#{}[{}{}]{}",
|
"#{}[{}{}]{}",
|
||||||
inner,
|
inner,
|
||||||
attr.path.display(self.db),
|
attr.path.display(self.db.upcast()),
|
||||||
attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
|
attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
|
||||||
separated_by,
|
separated_by,
|
||||||
);
|
);
|
||||||
|
@ -106,7 +104,7 @@ impl Printer<'_> {
|
||||||
|
|
||||||
fn print_visibility(&mut self, vis: RawVisibilityId) {
|
fn print_visibility(&mut self, vis: RawVisibilityId) {
|
||||||
match &self.tree[vis] {
|
match &self.tree[vis] {
|
||||||
RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db)),
|
RawVisibility::Module(path) => w!(self, "pub({}) ", path.display(self.db.upcast())),
|
||||||
RawVisibility::Public => w!(self, "pub "),
|
RawVisibility::Public => w!(self, "pub "),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -121,7 +119,7 @@ impl Printer<'_> {
|
||||||
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
||||||
this.print_attrs_of(field, "\n");
|
this.print_attrs_of(field, "\n");
|
||||||
this.print_visibility(*visibility);
|
this.print_visibility(*visibility);
|
||||||
w!(this, "{}: ", name.display(self.db));
|
w!(this, "{}: ", name.display(self.db.upcast()));
|
||||||
this.print_type_ref(type_ref);
|
this.print_type_ref(type_ref);
|
||||||
wln!(this, ",");
|
wln!(this, ",");
|
||||||
}
|
}
|
||||||
|
@ -135,7 +133,7 @@ impl Printer<'_> {
|
||||||
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
let Field { visibility, name, type_ref, ast_id: _ } = &this.tree[field];
|
||||||
this.print_attrs_of(field, "\n");
|
this.print_attrs_of(field, "\n");
|
||||||
this.print_visibility(*visibility);
|
this.print_visibility(*visibility);
|
||||||
w!(this, "{}: ", name.display(self.db));
|
w!(this, "{}: ", name.display(self.db.upcast()));
|
||||||
this.print_type_ref(type_ref);
|
this.print_type_ref(type_ref);
|
||||||
wln!(this, ",");
|
wln!(this, ",");
|
||||||
}
|
}
|
||||||
|
@ -168,20 +166,20 @@ impl Printer<'_> {
|
||||||
fn print_use_tree(&mut self, use_tree: &UseTree) {
|
fn print_use_tree(&mut self, use_tree: &UseTree) {
|
||||||
match &use_tree.kind {
|
match &use_tree.kind {
|
||||||
UseTreeKind::Single { path, alias } => {
|
UseTreeKind::Single { path, alias } => {
|
||||||
w!(self, "{}", path.display(self.db));
|
w!(self, "{}", path.display(self.db.upcast()));
|
||||||
if let Some(alias) = alias {
|
if let Some(alias) = alias {
|
||||||
w!(self, " as {}", alias);
|
w!(self, " as {}", alias);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UseTreeKind::Glob { path } => {
|
UseTreeKind::Glob { path } => {
|
||||||
if let Some(path) = path {
|
if let Some(path) = path {
|
||||||
w!(self, "{}::", path.display(self.db));
|
w!(self, "{}::", path.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
w!(self, "*");
|
w!(self, "*");
|
||||||
}
|
}
|
||||||
UseTreeKind::Prefixed { prefix, list } => {
|
UseTreeKind::Prefixed { prefix, list } => {
|
||||||
if let Some(prefix) = prefix {
|
if let Some(prefix) = prefix {
|
||||||
w!(self, "{}::", prefix.display(self.db));
|
w!(self, "{}::", prefix.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
w!(self, "{{");
|
w!(self, "{{");
|
||||||
for (i, tree) in list.iter().enumerate() {
|
for (i, tree) in list.iter().enumerate() {
|
||||||
|
@ -209,7 +207,7 @@ impl Printer<'_> {
|
||||||
ModItem::ExternCrate(it) => {
|
ModItem::ExternCrate(it) => {
|
||||||
let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
|
let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
w!(self, "extern crate {}", name.display(self.db));
|
w!(self, "extern crate {}", name.display(self.db.upcast()));
|
||||||
if let Some(alias) = alias {
|
if let Some(alias) = alias {
|
||||||
w!(self, " as {}", alias);
|
w!(self, " as {}", alias);
|
||||||
}
|
}
|
||||||
|
@ -256,7 +254,7 @@ impl Printer<'_> {
|
||||||
if let Some(abi) = abi {
|
if let Some(abi) = abi {
|
||||||
w!(self, "extern \"{}\" ", abi);
|
w!(self, "extern \"{}\" ", abi);
|
||||||
}
|
}
|
||||||
w!(self, "fn {}", name.display(self.db));
|
w!(self, "fn {}", name.display(self.db.upcast()));
|
||||||
self.print_generic_params(explicit_generic_params);
|
self.print_generic_params(explicit_generic_params);
|
||||||
w!(self, "(");
|
w!(self, "(");
|
||||||
if !params.is_empty() {
|
if !params.is_empty() {
|
||||||
|
@ -290,7 +288,7 @@ impl Printer<'_> {
|
||||||
ModItem::Struct(it) => {
|
ModItem::Struct(it) => {
|
||||||
let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
|
let Struct { visibility, name, fields, generic_params, ast_id: _ } = &self.tree[it];
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
w!(self, "struct {}", name.display(self.db));
|
w!(self, "struct {}", name.display(self.db.upcast()));
|
||||||
self.print_generic_params(generic_params);
|
self.print_generic_params(generic_params);
|
||||||
self.print_fields_and_where_clause(fields, generic_params);
|
self.print_fields_and_where_clause(fields, generic_params);
|
||||||
if matches!(fields, Fields::Record(_)) {
|
if matches!(fields, Fields::Record(_)) {
|
||||||
|
@ -302,7 +300,7 @@ impl Printer<'_> {
|
||||||
ModItem::Union(it) => {
|
ModItem::Union(it) => {
|
||||||
let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
|
let Union { name, visibility, fields, generic_params, ast_id: _ } = &self.tree[it];
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
w!(self, "union {}", name.display(self.db));
|
w!(self, "union {}", name.display(self.db.upcast()));
|
||||||
self.print_generic_params(generic_params);
|
self.print_generic_params(generic_params);
|
||||||
self.print_fields_and_where_clause(fields, generic_params);
|
self.print_fields_and_where_clause(fields, generic_params);
|
||||||
if matches!(fields, Fields::Record(_)) {
|
if matches!(fields, Fields::Record(_)) {
|
||||||
|
@ -314,14 +312,14 @@ impl Printer<'_> {
|
||||||
ModItem::Enum(it) => {
|
ModItem::Enum(it) => {
|
||||||
let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
|
let Enum { name, visibility, variants, generic_params, ast_id: _ } = &self.tree[it];
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
w!(self, "enum {}", name.display(self.db));
|
w!(self, "enum {}", name.display(self.db.upcast()));
|
||||||
self.print_generic_params(generic_params);
|
self.print_generic_params(generic_params);
|
||||||
self.print_where_clause_and_opening_brace(generic_params);
|
self.print_where_clause_and_opening_brace(generic_params);
|
||||||
self.indented(|this| {
|
self.indented(|this| {
|
||||||
for variant in variants.clone() {
|
for variant in variants.clone() {
|
||||||
let Variant { name, fields, ast_id: _ } = &this.tree[variant];
|
let Variant { name, fields, ast_id: _ } = &this.tree[variant];
|
||||||
this.print_attrs_of(variant, "\n");
|
this.print_attrs_of(variant, "\n");
|
||||||
w!(this, "{}", name.display(self.db));
|
w!(this, "{}", name.display(self.db.upcast()));
|
||||||
this.print_fields(fields);
|
this.print_fields(fields);
|
||||||
wln!(this, ",");
|
wln!(this, ",");
|
||||||
}
|
}
|
||||||
|
@ -333,7 +331,7 @@ impl Printer<'_> {
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
w!(self, "const ");
|
w!(self, "const ");
|
||||||
match name {
|
match name {
|
||||||
Some(name) => w!(self, "{}", name.display(self.db)),
|
Some(name) => w!(self, "{}", name.display(self.db.upcast())),
|
||||||
None => w!(self, "_"),
|
None => w!(self, "_"),
|
||||||
}
|
}
|
||||||
w!(self, ": ");
|
w!(self, ": ");
|
||||||
|
@ -347,7 +345,7 @@ impl Printer<'_> {
|
||||||
if *mutable {
|
if *mutable {
|
||||||
w!(self, "mut ");
|
w!(self, "mut ");
|
||||||
}
|
}
|
||||||
w!(self, "{}: ", name.display(self.db));
|
w!(self, "{}: ", name.display(self.db.upcast()));
|
||||||
self.print_type_ref(type_ref);
|
self.print_type_ref(type_ref);
|
||||||
w!(self, " = _;");
|
w!(self, " = _;");
|
||||||
wln!(self);
|
wln!(self);
|
||||||
|
@ -369,7 +367,7 @@ impl Printer<'_> {
|
||||||
if *is_auto {
|
if *is_auto {
|
||||||
w!(self, "auto ");
|
w!(self, "auto ");
|
||||||
}
|
}
|
||||||
w!(self, "trait {}", name.display(self.db));
|
w!(self, "trait {}", name.display(self.db.upcast()));
|
||||||
self.print_generic_params(generic_params);
|
self.print_generic_params(generic_params);
|
||||||
self.print_where_clause_and_opening_brace(generic_params);
|
self.print_where_clause_and_opening_brace(generic_params);
|
||||||
self.indented(|this| {
|
self.indented(|this| {
|
||||||
|
@ -382,7 +380,7 @@ impl Printer<'_> {
|
||||||
ModItem::TraitAlias(it) => {
|
ModItem::TraitAlias(it) => {
|
||||||
let TraitAlias { name, visibility, generic_params, ast_id: _ } = &self.tree[it];
|
let TraitAlias { name, visibility, generic_params, ast_id: _ } = &self.tree[it];
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
w!(self, "trait {}", name.display(self.db));
|
w!(self, "trait {}", name.display(self.db.upcast()));
|
||||||
self.print_generic_params(generic_params);
|
self.print_generic_params(generic_params);
|
||||||
w!(self, " = ");
|
w!(self, " = ");
|
||||||
self.print_where_clause(generic_params);
|
self.print_where_clause(generic_params);
|
||||||
|
@ -415,7 +413,7 @@ impl Printer<'_> {
|
||||||
let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
|
let TypeAlias { name, visibility, bounds, type_ref, generic_params, ast_id: _ } =
|
||||||
&self.tree[it];
|
&self.tree[it];
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
w!(self, "type {}", name.display(self.db));
|
w!(self, "type {}", name.display(self.db.upcast()));
|
||||||
self.print_generic_params(generic_params);
|
self.print_generic_params(generic_params);
|
||||||
if !bounds.is_empty() {
|
if !bounds.is_empty() {
|
||||||
w!(self, ": ");
|
w!(self, ": ");
|
||||||
|
@ -432,7 +430,7 @@ impl Printer<'_> {
|
||||||
ModItem::Mod(it) => {
|
ModItem::Mod(it) => {
|
||||||
let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it];
|
let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it];
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
w!(self, "mod {}", name.display(self.db));
|
w!(self, "mod {}", name.display(self.db.upcast()));
|
||||||
match kind {
|
match kind {
|
||||||
ModKind::Inline { items } => {
|
ModKind::Inline { items } => {
|
||||||
w!(self, " {{");
|
w!(self, " {{");
|
||||||
|
@ -450,16 +448,16 @@ impl Printer<'_> {
|
||||||
}
|
}
|
||||||
ModItem::MacroCall(it) => {
|
ModItem::MacroCall(it) => {
|
||||||
let MacroCall { path, ast_id: _, expand_to: _ } = &self.tree[it];
|
let MacroCall { path, ast_id: _, expand_to: _ } = &self.tree[it];
|
||||||
wln!(self, "{}!(...);", path.display(self.db));
|
wln!(self, "{}!(...);", path.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
ModItem::MacroRules(it) => {
|
ModItem::MacroRules(it) => {
|
||||||
let MacroRules { name, ast_id: _ } = &self.tree[it];
|
let MacroRules { name, ast_id: _ } = &self.tree[it];
|
||||||
wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db));
|
wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
ModItem::MacroDef(it) => {
|
ModItem::MacroDef(it) => {
|
||||||
let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
|
let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
wln!(self, "macro {} {{ ... }}", name.display(self.db));
|
wln!(self, "macro {} {{ ... }}", name.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,7 +489,7 @@ impl Printer<'_> {
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
self.print_attrs_of(idx, " ");
|
self.print_attrs_of(idx, " ");
|
||||||
w!(self, "{}", lt.name.display(self.db));
|
w!(self, "{}", lt.name.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
for (idx, x) in params.type_or_consts.iter() {
|
for (idx, x) in params.type_or_consts.iter() {
|
||||||
if !first {
|
if !first {
|
||||||
|
@ -501,11 +499,11 @@ impl Printer<'_> {
|
||||||
self.print_attrs_of(idx, " ");
|
self.print_attrs_of(idx, " ");
|
||||||
match x {
|
match x {
|
||||||
TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
|
TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
|
||||||
Some(name) => w!(self, "{}", name.display(self.db)),
|
Some(name) => w!(self, "{}", name.display(self.db.upcast())),
|
||||||
None => w!(self, "_anon_{}", idx.into_raw()),
|
None => w!(self, "_anon_{}", idx.into_raw()),
|
||||||
},
|
},
|
||||||
TypeOrConstParamData::ConstParamData(konst) => {
|
TypeOrConstParamData::ConstParamData(konst) => {
|
||||||
w!(self, "const {}: ", konst.name.display(self.db));
|
w!(self, "const {}: ", konst.name.display(self.db.upcast()));
|
||||||
self.print_type_ref(&konst.ty);
|
self.print_type_ref(&konst.ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -540,8 +538,8 @@ impl Printer<'_> {
|
||||||
wln!(
|
wln!(
|
||||||
this,
|
this,
|
||||||
"{}: {},",
|
"{}: {},",
|
||||||
target.name.display(self.db),
|
target.name.display(self.db.upcast()),
|
||||||
bound.name.display(self.db)
|
bound.name.display(self.db.upcast())
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -551,7 +549,7 @@ impl Printer<'_> {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
w!(this, ", ");
|
w!(this, ", ");
|
||||||
}
|
}
|
||||||
w!(this, "{}", lt.display(self.db));
|
w!(this, "{}", lt.display(self.db.upcast()));
|
||||||
}
|
}
|
||||||
w!(this, "> ");
|
w!(this, "> ");
|
||||||
(target, bound)
|
(target, bound)
|
||||||
|
@ -562,7 +560,7 @@ impl Printer<'_> {
|
||||||
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
|
WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
|
||||||
WherePredicateTypeTarget::TypeOrConstParam(id) => {
|
WherePredicateTypeTarget::TypeOrConstParam(id) => {
|
||||||
match ¶ms.type_or_consts[*id].name() {
|
match ¶ms.type_or_consts[*id].name() {
|
||||||
Some(name) => w!(this, "{}", name.display(self.db)),
|
Some(name) => w!(this, "{}", name.display(self.db.upcast())),
|
||||||
None => w!(this, "_anon_{}", id.into_raw()),
|
None => w!(this, "_anon_{}", id.into_raw()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
//!
|
//!
|
||||||
//! This attribute to tell the compiler about semi built-in std library
|
//! This attribute to tell the compiler about semi built-in std library
|
||||||
//! features, such as Fn family of traits.
|
//! features, such as Fn family of traits.
|
||||||
|
use hir_expand::name::Name;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use syntax::SmolStr;
|
use syntax::SmolStr;
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
@ -238,7 +239,17 @@ impl LangItem {
|
||||||
|
|
||||||
pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option<Path> {
|
pub fn path(&self, db: &dyn DefDatabase, start_crate: CrateId) -> Option<Path> {
|
||||||
let t = db.lang_item(start_crate, *self)?;
|
let t = db.lang_item(start_crate, *self)?;
|
||||||
Some(Path::LangItem(t))
|
Some(Path::LangItem(t, None))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ty_rel_path(
|
||||||
|
&self,
|
||||||
|
db: &dyn DefDatabase,
|
||||||
|
start_crate: CrateId,
|
||||||
|
seg: Name,
|
||||||
|
) -> Option<Path> {
|
||||||
|
let t = db.lang_item(start_crate, *self)?;
|
||||||
|
Some(Path::LangItem(t, Some(seg)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -240,7 +240,7 @@ macro_rules! format_args {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(arg1(a, b, c)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(arg2), ::core::fmt::Debug::fmt), ]);
|
builtin #format_args ("{} {:?}", arg1(a, b, c), arg2);
|
||||||
}
|
}
|
||||||
"##]],
|
"##]],
|
||||||
);
|
);
|
||||||
|
@ -258,10 +258,10 @@ macro_rules! format_args {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
format_args!(x = 2);
|
format_args!(x = 2);
|
||||||
format_args!(x =);
|
format_args!/*+errors*/(x =);
|
||||||
format_args!(x =, x = 2);
|
format_args!/*+errors*/(x =, x = 2);
|
||||||
format_args!("{}", x =);
|
format_args!/*+errors*/("{}", x =);
|
||||||
format_args!(=, "{}", x =);
|
format_args!/*+errors*/(=, "{}", x =);
|
||||||
format_args!(x = 2, "{}", 5);
|
format_args!(x = 2, "{}", 5);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
|
@ -273,12 +273,19 @@ macro_rules! format_args {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
/* error: no rule matches input tokens */;
|
builtin #format_args (x = 2);
|
||||||
/* error: expected expression */;
|
/* parse error: expected expression */
|
||||||
/* error: expected expression, expected COMMA */;
|
builtin #format_args (x = );
|
||||||
/* error: expected expression */::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(), ::core::fmt::Display::fmt), ]);
|
/* parse error: expected expression */
|
||||||
/* error: expected expression, expected R_PAREN */;
|
/* parse error: expected R_PAREN */
|
||||||
::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(5), ::core::fmt::Display::fmt), ]);
|
/* parse error: expected expression, item or let statement */
|
||||||
|
builtin #format_args (x = , x = 2);
|
||||||
|
/* parse error: expected expression */
|
||||||
|
builtin #format_args ("{}", x = );
|
||||||
|
/* parse error: expected expression */
|
||||||
|
/* parse error: expected expression */
|
||||||
|
builtin #format_args ( = , "{}", x = );
|
||||||
|
builtin #format_args (x = 2, "{}", 5);
|
||||||
}
|
}
|
||||||
"##]],
|
"##]],
|
||||||
);
|
);
|
||||||
|
@ -306,7 +313,7 @@ macro_rules! format_args {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a::<A, B>()), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
|
builtin #format_args ("{} {:?}", a::<A, B>(), b);
|
||||||
}
|
}
|
||||||
"##]],
|
"##]],
|
||||||
);
|
);
|
||||||
|
@ -339,7 +346,7 @@ macro_rules! format_args {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
::core::fmt::Arguments::new_v1(&[r#""#, r#",mismatch,""#, r#"",""#, r#"""#, ], &[::core::fmt::ArgumentV1::new(&(location_csv_pat(db, &analysis, vfs, &sm, pat_id)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.expected.display(db)), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(mismatch.actual.display(db)), ::core::fmt::Display::fmt), ]);
|
builtin #format_args (r#"{},mismatch,"{}","{}""#, location_csv_pat(db, &analysis, vfs, &sm, pat_id), mismatch.expected.display(db), mismatch.actual.display(db));
|
||||||
}
|
}
|
||||||
"##]],
|
"##]],
|
||||||
);
|
);
|
||||||
|
@ -373,7 +380,7 @@ macro_rules! format_args {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
::core::fmt::Arguments::new_v1(&["xxx", "y", "zzz", ], &[::core::fmt::ArgumentV1::new(&(2), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(b), ::core::fmt::Debug::fmt), ]);
|
builtin #format_args (concat!("xxx{}y", "{:?}zzz"), 2, b);
|
||||||
}
|
}
|
||||||
"##]],
|
"##]],
|
||||||
);
|
);
|
||||||
|
@ -403,8 +410,8 @@ macro_rules! format_args {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ =
|
let _ =
|
||||||
/* error: expected field name or number *//* parse error: expected field name or number */
|
/* parse error: expected field name or number */
|
||||||
::core::fmt::Arguments::new_v1(&["", " ", ], &[::core::fmt::ArgumentV1::new(&(a.), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(), ::core::fmt::Debug::fmt), ]);
|
builtin #format_args ("{} {:?}", a.);
|
||||||
}
|
}
|
||||||
"##]],
|
"##]],
|
||||||
);
|
);
|
||||||
|
|
|
@ -117,7 +117,7 @@ fn main(foo: ()) {
|
||||||
macro_rules! format_args {}
|
macro_rules! format_args {}
|
||||||
|
|
||||||
fn main(foo: ()) {
|
fn main(foo: ()) {
|
||||||
/* error: unresolved macro identity */::core::fmt::Arguments::new_v1(&["", " ", " ", ], &[::core::fmt::ArgumentV1::new(&(::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(0), ::core::fmt::Display::fmt), ])), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(foo), ::core::fmt::Display::fmt), ::core::fmt::ArgumentV1::new(&(identity!(10)), ::core::fmt::Display::fmt), ])
|
builtin #format_args ("{} {} {}", format_args!("{}", 0), foo, identity!(10), "bar")
|
||||||
}
|
}
|
||||||
"##]],
|
"##]],
|
||||||
);
|
);
|
||||||
|
@ -150,8 +150,8 @@ macro_rules! identity {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main(foo: ()) {
|
fn main(foo: ()) {
|
||||||
// format_args/*+tokenids*/!("{} {} {}"#1,#3 format_args!("{}", 0#10),#12 foo#13,#14 identity!(10#18),#21 "bar"#22)
|
// format_args/*+tokenids*/!("{} {} {}"#1,#2 format_args#3!#4("{}"#6,#7 0#8),#9 foo#10,#11 identity#12!#13(10#15),#16 "bar"#17)
|
||||||
::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(�[#4294967295""#4294967295,#4294967295 " "#4294967295,#4294967295 " "#4294967295,#4294967295 ]#4294967295,#4294967295 �[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(�(::core#4294967295::fmt#4294967295::Arguments#4294967295::new_v1#4294967295(�[#4294967295""#4294967295,#4294967295 ]#4294967295,#4294967295 �[::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(�(#42949672950#10)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(�(#4294967295foo#13)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::ArgumentV1#4294967295::new#4294967295(�(#429496729510#18)#4294967295,#4294967295 ::core#4294967295::fmt#4294967295::Display#4294967295::fmt#4294967295)#4294967295,#4294967295 ]#4294967295)#4294967295
|
builtin#4294967295 ##4294967295format_args#4294967295 (#0"{} {} {}"#1,#2 format_args#3!#4(#5"{}"#6,#7 0#8)#5,#9 foo#10,#11 identity#12!#13(#1410#15)#14,#16 "bar"#17)#0
|
||||||
}
|
}
|
||||||
|
|
||||||
"##]],
|
"##]],
|
||||||
|
|
|
@ -929,8 +929,8 @@ fn main() {
|
||||||
macro_rules! format_args {}
|
macro_rules! format_args {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
/* error: expected field name or number *//* parse error: expected field name or number */
|
/* parse error: expected field name or number */
|
||||||
::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(line.1.), ::core::fmt::Display::fmt), ]);
|
builtin #format_args ("{}", line.1.);
|
||||||
}
|
}
|
||||||
|
|
||||||
"##]],
|
"##]],
|
||||||
|
@ -956,19 +956,15 @@ fn main() {
|
||||||
macro_rules! format_args {}
|
macro_rules! format_args {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
/* error: expected COMMA, expected R_BRACK, expected COMMA, expected COMMA, expected expression, expected R_PAREN *//* parse error: expected COMMA */
|
/* parse error: expected COMMA */
|
||||||
/* parse error: expected R_BRACK */
|
/* parse error: expected R_BRACK */
|
||||||
/* parse error: expected COMMA */
|
/* parse error: expected COMMA */
|
||||||
/* parse error: expected COMMA */
|
/* parse error: expected COMMA */
|
||||||
/* parse error: expected expression */
|
/* parse error: expected expression */
|
||||||
/* parse error: expected R_PAREN */
|
/* parse error: expected R_PAREN */
|
||||||
/* parse error: expected R_PAREN */
|
|
||||||
/* parse error: expected expression, item or let statement */
|
/* parse error: expected expression, item or let statement */
|
||||||
/* parse error: expected expression, item or let statement */
|
/* parse error: expected expression, item or let statement */
|
||||||
/* parse error: expected expression, item or let statement */
|
builtin #format_args ("{}", &[0 2]);
|
||||||
/* parse error: expected expression, item or let statement */
|
|
||||||
/* parse error: expected expression, item or let statement */
|
|
||||||
::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(&[0 2]), ::core::fmt::Display::fmt), ]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"##]],
|
"##]],
|
||||||
|
|
|
@ -47,7 +47,7 @@ pub enum Path {
|
||||||
},
|
},
|
||||||
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
|
/// A link to a lang item. It is used in desugaring of things like `it?`. We can show these
|
||||||
/// links via a normal path since they might be private and not accessible in the usage place.
|
/// links via a normal path since they might be private and not accessible in the usage place.
|
||||||
LangItem(LangItemTarget),
|
LangItem(LangItemTarget, Option<Name>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
|
/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
|
||||||
|
@ -122,33 +122,40 @@ impl Path {
|
||||||
pub fn kind(&self) -> &PathKind {
|
pub fn kind(&self) -> &PathKind {
|
||||||
match self {
|
match self {
|
||||||
Path::Normal { mod_path, .. } => &mod_path.kind,
|
Path::Normal { mod_path, .. } => &mod_path.kind,
|
||||||
Path::LangItem(_) => &PathKind::Abs,
|
Path::LangItem(..) => &PathKind::Abs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_anchor(&self) -> Option<&TypeRef> {
|
pub fn type_anchor(&self) -> Option<&TypeRef> {
|
||||||
match self {
|
match self {
|
||||||
Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
|
Path::Normal { type_anchor, .. } => type_anchor.as_deref(),
|
||||||
Path::LangItem(_) => None,
|
Path::LangItem(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn segments(&self) -> PathSegments<'_> {
|
pub fn segments(&self) -> PathSegments<'_> {
|
||||||
let Path::Normal { mod_path, generic_args, .. } = self else {
|
match self {
|
||||||
return PathSegments { segments: &[], generic_args: None };
|
Path::Normal { mod_path, generic_args, .. } => {
|
||||||
};
|
let s = PathSegments {
|
||||||
let s =
|
segments: mod_path.segments(),
|
||||||
PathSegments { segments: mod_path.segments(), generic_args: generic_args.as_deref() };
|
generic_args: generic_args.as_deref(),
|
||||||
if let Some(generic_args) = s.generic_args {
|
};
|
||||||
assert_eq!(s.segments.len(), generic_args.len());
|
if let Some(generic_args) = s.generic_args {
|
||||||
|
assert_eq!(s.segments.len(), generic_args.len());
|
||||||
|
}
|
||||||
|
s
|
||||||
|
}
|
||||||
|
Path::LangItem(_, seg) => PathSegments {
|
||||||
|
segments: seg.as_ref().map_or(&[], |seg| std::slice::from_ref(seg)),
|
||||||
|
generic_args: None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mod_path(&self) -> Option<&ModPath> {
|
pub fn mod_path(&self) -> Option<&ModPath> {
|
||||||
match self {
|
match self {
|
||||||
Path::Normal { mod_path, .. } => Some(&mod_path),
|
Path::Normal { mod_path, .. } => Some(&mod_path),
|
||||||
Path::LangItem(_) => None,
|
Path::LangItem(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,54 @@
|
||||||
|
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
|
|
||||||
use hir_expand::{db::ExpandDatabase, mod_path::PathKind};
|
use hir_expand::mod_path::PathKind;
|
||||||
use intern::Interned;
|
use intern::Interned;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
db::DefDatabase,
|
||||||
|
lang_item::LangItemTarget,
|
||||||
path::{GenericArg, GenericArgs, Path},
|
path::{GenericArg, GenericArgs, Path},
|
||||||
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
|
type_ref::{Mutability, TraitBoundModifier, TypeBound, TypeRef},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result {
|
pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) -> fmt::Result {
|
||||||
if let Path::LangItem(it) = path {
|
if let Path::LangItem(it, s) = path {
|
||||||
return write!(buf, "$lang_item::{it:?}");
|
write!(buf, "builtin#lang(")?;
|
||||||
|
match *it {
|
||||||
|
LangItemTarget::ImplDef(it) => write!(buf, "{it:?}")?,
|
||||||
|
LangItemTarget::EnumId(it) => {
|
||||||
|
write!(buf, "{}", db.enum_data(it).name.display(db.upcast()))?
|
||||||
|
}
|
||||||
|
LangItemTarget::Function(it) => {
|
||||||
|
write!(buf, "{}", db.function_data(it).name.display(db.upcast()))?
|
||||||
|
}
|
||||||
|
LangItemTarget::Static(it) => {
|
||||||
|
write!(buf, "{}", db.static_data(it).name.display(db.upcast()))?
|
||||||
|
}
|
||||||
|
LangItemTarget::Struct(it) => {
|
||||||
|
write!(buf, "{}", db.struct_data(it).name.display(db.upcast()))?
|
||||||
|
}
|
||||||
|
LangItemTarget::Union(it) => {
|
||||||
|
write!(buf, "{}", db.union_data(it).name.display(db.upcast()))?
|
||||||
|
}
|
||||||
|
LangItemTarget::TypeAlias(it) => {
|
||||||
|
write!(buf, "{}", db.type_alias_data(it).name.display(db.upcast()))?
|
||||||
|
}
|
||||||
|
LangItemTarget::Trait(it) => {
|
||||||
|
write!(buf, "{}", db.trait_data(it).name.display(db.upcast()))?
|
||||||
|
}
|
||||||
|
LangItemTarget::EnumVariant(it) => write!(
|
||||||
|
buf,
|
||||||
|
"{}",
|
||||||
|
db.enum_data(it.parent).variants[it.local_id].name.display(db.upcast())
|
||||||
|
)?,
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(s) = s {
|
||||||
|
write!(buf, "::{}", s.display(db.upcast()))?;
|
||||||
|
}
|
||||||
|
return write!(buf, ")");
|
||||||
}
|
}
|
||||||
match path.type_anchor() {
|
match path.type_anchor() {
|
||||||
Some(anchor) => {
|
Some(anchor) => {
|
||||||
|
@ -44,7 +80,7 @@ pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Wri
|
||||||
write!(buf, "::")?;
|
write!(buf, "::")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(buf, "{}", segment.name.display(db))?;
|
write!(buf, "{}", segment.name.display(db.upcast()))?;
|
||||||
if let Some(generics) = segment.args_and_bindings {
|
if let Some(generics) = segment.args_and_bindings {
|
||||||
write!(buf, "::<")?;
|
write!(buf, "::<")?;
|
||||||
print_generic_args(db, generics, buf)?;
|
print_generic_args(db, generics, buf)?;
|
||||||
|
@ -57,7 +93,7 @@ pub(crate) fn print_path(db: &dyn ExpandDatabase, path: &Path, buf: &mut dyn Wri
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_generic_args(
|
pub(crate) fn print_generic_args(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn DefDatabase,
|
||||||
generics: &GenericArgs,
|
generics: &GenericArgs,
|
||||||
buf: &mut dyn Write,
|
buf: &mut dyn Write,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
|
@ -83,7 +119,7 @@ pub(crate) fn print_generic_args(
|
||||||
write!(buf, ", ")?;
|
write!(buf, ", ")?;
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
write!(buf, "{}", binding.name.display(db))?;
|
write!(buf, "{}", binding.name.display(db.upcast()))?;
|
||||||
if !binding.bounds.is_empty() {
|
if !binding.bounds.is_empty() {
|
||||||
write!(buf, ": ")?;
|
write!(buf, ": ")?;
|
||||||
print_type_bounds(db, &binding.bounds, buf)?;
|
print_type_bounds(db, &binding.bounds, buf)?;
|
||||||
|
@ -97,19 +133,19 @@ pub(crate) fn print_generic_args(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_generic_arg(
|
pub(crate) fn print_generic_arg(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn DefDatabase,
|
||||||
arg: &GenericArg,
|
arg: &GenericArg,
|
||||||
buf: &mut dyn Write,
|
buf: &mut dyn Write,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
match arg {
|
match arg {
|
||||||
GenericArg::Type(ty) => print_type_ref(db, ty, buf),
|
GenericArg::Type(ty) => print_type_ref(db, ty, buf),
|
||||||
GenericArg::Const(c) => write!(buf, "{}", c.display(db)),
|
GenericArg::Const(c) => write!(buf, "{}", c.display(db.upcast())),
|
||||||
GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db)),
|
GenericArg::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_type_ref(
|
pub(crate) fn print_type_ref(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn DefDatabase,
|
||||||
type_ref: &TypeRef,
|
type_ref: &TypeRef,
|
||||||
buf: &mut dyn Write,
|
buf: &mut dyn Write,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
|
@ -143,7 +179,7 @@ pub(crate) fn print_type_ref(
|
||||||
};
|
};
|
||||||
write!(buf, "&")?;
|
write!(buf, "&")?;
|
||||||
if let Some(lt) = lt {
|
if let Some(lt) = lt {
|
||||||
write!(buf, "{} ", lt.name.display(db))?;
|
write!(buf, "{} ", lt.name.display(db.upcast()))?;
|
||||||
}
|
}
|
||||||
write!(buf, "{mtbl}")?;
|
write!(buf, "{mtbl}")?;
|
||||||
print_type_ref(db, pointee, buf)?;
|
print_type_ref(db, pointee, buf)?;
|
||||||
|
@ -151,7 +187,7 @@ pub(crate) fn print_type_ref(
|
||||||
TypeRef::Array(elem, len) => {
|
TypeRef::Array(elem, len) => {
|
||||||
write!(buf, "[")?;
|
write!(buf, "[")?;
|
||||||
print_type_ref(db, elem, buf)?;
|
print_type_ref(db, elem, buf)?;
|
||||||
write!(buf, "; {}]", len.display(db))?;
|
write!(buf, "; {}]", len.display(db.upcast()))?;
|
||||||
}
|
}
|
||||||
TypeRef::Slice(elem) => {
|
TypeRef::Slice(elem) => {
|
||||||
write!(buf, "[")?;
|
write!(buf, "[")?;
|
||||||
|
@ -198,7 +234,7 @@ pub(crate) fn print_type_ref(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_type_bounds(
|
pub(crate) fn print_type_bounds(
|
||||||
db: &dyn ExpandDatabase,
|
db: &dyn DefDatabase,
|
||||||
bounds: &[Interned<TypeBound>],
|
bounds: &[Interned<TypeBound>],
|
||||||
buf: &mut dyn Write,
|
buf: &mut dyn Write,
|
||||||
) -> fmt::Result {
|
) -> fmt::Result {
|
||||||
|
@ -216,10 +252,14 @@ pub(crate) fn print_type_bounds(
|
||||||
print_path(db, path, buf)?;
|
print_path(db, path, buf)?;
|
||||||
}
|
}
|
||||||
TypeBound::ForLifetime(lifetimes, path) => {
|
TypeBound::ForLifetime(lifetimes, path) => {
|
||||||
write!(buf, "for<{}> ", lifetimes.iter().map(|it| it.display(db)).format(", "))?;
|
write!(
|
||||||
|
buf,
|
||||||
|
"for<{}> ",
|
||||||
|
lifetimes.iter().map(|it| it.display(db.upcast())).format(", ")
|
||||||
|
)?;
|
||||||
print_path(db, path, buf)?;
|
print_path(db, path, buf)?;
|
||||||
}
|
}
|
||||||
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db))?,
|
TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast()))?,
|
||||||
TypeBound::Error => write!(buf, "{{unknown}}")?,
|
TypeBound::Error => write!(buf, "{{unknown}}")?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,22 +156,19 @@ impl Resolver {
|
||||||
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
|
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> {
|
||||||
let path = match path {
|
let path = match path {
|
||||||
Path::Normal { mod_path, .. } => mod_path,
|
Path::Normal { mod_path, .. } => mod_path,
|
||||||
Path::LangItem(l) => {
|
Path::LangItem(l, seg) => {
|
||||||
return Some((
|
let type_ns = match *l {
|
||||||
match *l {
|
LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
|
||||||
LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
|
LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
|
||||||
LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
|
LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
|
||||||
LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
|
LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
|
||||||
LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
|
LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
|
||||||
LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
|
LangItemTarget::Trait(it) => TypeNs::TraitId(it),
|
||||||
LangItemTarget::Trait(it) => TypeNs::TraitId(it),
|
LangItemTarget::Function(_)
|
||||||
LangItemTarget::Function(_)
|
| LangItemTarget::ImplDef(_)
|
||||||
| LangItemTarget::ImplDef(_)
|
| LangItemTarget::Static(_) => return None,
|
||||||
| LangItemTarget::Static(_) => return None,
|
};
|
||||||
},
|
return Some((type_ns, seg.as_ref().map(|_| 1), None));
|
||||||
None,
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let first_name = path.segments().first()?;
|
let first_name = path.segments().first()?;
|
||||||
|
@ -256,7 +253,7 @@ impl Resolver {
|
||||||
) -> Option<ResolveValueResult> {
|
) -> Option<ResolveValueResult> {
|
||||||
let path = match path {
|
let path = match path {
|
||||||
Path::Normal { mod_path, .. } => mod_path,
|
Path::Normal { mod_path, .. } => mod_path,
|
||||||
Path::LangItem(l) => {
|
Path::LangItem(l, None) => {
|
||||||
return Some(ResolveValueResult::ValueNs(
|
return Some(ResolveValueResult::ValueNs(
|
||||||
match *l {
|
match *l {
|
||||||
LangItemTarget::Function(it) => ValueNs::FunctionId(it),
|
LangItemTarget::Function(it) => ValueNs::FunctionId(it),
|
||||||
|
@ -272,6 +269,20 @@ impl Resolver {
|
||||||
None,
|
None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
Path::LangItem(l, Some(_)) => {
|
||||||
|
let type_ns = match *l {
|
||||||
|
LangItemTarget::Union(it) => TypeNs::AdtId(it.into()),
|
||||||
|
LangItemTarget::TypeAlias(it) => TypeNs::TypeAliasId(it),
|
||||||
|
LangItemTarget::Struct(it) => TypeNs::AdtId(it.into()),
|
||||||
|
LangItemTarget::EnumVariant(it) => TypeNs::EnumVariantId(it),
|
||||||
|
LangItemTarget::EnumId(it) => TypeNs::AdtId(it.into()),
|
||||||
|
LangItemTarget::Trait(it) => TypeNs::TraitId(it),
|
||||||
|
LangItemTarget::Function(_)
|
||||||
|
| LangItemTarget::ImplDef(_)
|
||||||
|
| LangItemTarget::Static(_) => return None,
|
||||||
|
};
|
||||||
|
return Some(ResolveValueResult::Partial(type_ns, 1, None));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let n_segments = path.segments().len();
|
let n_segments = path.segments().len();
|
||||||
let tmp = name![self];
|
let tmp = name![self];
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
//! Builtin macro
|
//! Builtin macro
|
||||||
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
use ::tt::Ident;
|
|
||||||
use base_db::{AnchoredPath, Edition, FileId};
|
use base_db::{AnchoredPath, Edition, FileId};
|
||||||
use cfg::CfgExpr;
|
use cfg::CfgExpr;
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use mbe::{parse_exprs_with_sep, parse_to_token_tree, TokenMap};
|
use mbe::{parse_exprs_with_sep, parse_to_token_tree, TokenMap};
|
||||||
use rustc_hash::FxHashMap;
|
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, AstToken},
|
ast::{self, AstToken},
|
||||||
SmolStr,
|
SmolStr,
|
||||||
|
@ -97,11 +93,11 @@ register_builtin! {
|
||||||
(unreachable, Unreachable) => unreachable_expand,
|
(unreachable, Unreachable) => unreachable_expand,
|
||||||
(log_syntax, LogSyntax) => log_syntax_expand,
|
(log_syntax, LogSyntax) => log_syntax_expand,
|
||||||
(trace_macros, TraceMacros) => trace_macros_expand,
|
(trace_macros, TraceMacros) => trace_macros_expand,
|
||||||
|
|
||||||
EAGER:
|
|
||||||
(format_args, FormatArgs) => format_args_expand,
|
(format_args, FormatArgs) => format_args_expand,
|
||||||
(const_format_args, ConstFormatArgs) => format_args_expand,
|
(const_format_args, ConstFormatArgs) => format_args_expand,
|
||||||
(format_args_nl, FormatArgsNl) => format_args_nl_expand,
|
(format_args_nl, FormatArgsNl) => format_args_nl_expand,
|
||||||
|
|
||||||
|
EAGER:
|
||||||
(compile_error, CompileError) => compile_error_expand,
|
(compile_error, CompileError) => compile_error_expand,
|
||||||
(concat, Concat) => concat_expand,
|
(concat, Concat) => concat_expand,
|
||||||
(concat_idents, ConcatIdents) => concat_idents_expand,
|
(concat_idents, ConcatIdents) => concat_idents_expand,
|
||||||
|
@ -247,151 +243,15 @@ fn format_args_expand_general(
|
||||||
_db: &dyn ExpandDatabase,
|
_db: &dyn ExpandDatabase,
|
||||||
_id: MacroCallId,
|
_id: MacroCallId,
|
||||||
tt: &tt::Subtree,
|
tt: &tt::Subtree,
|
||||||
end_string: &str,
|
// FIXME: Make use of this so that mir interpretation works properly
|
||||||
|
_end_string: &str,
|
||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<tt::Subtree> {
|
||||||
let args = parse_exprs_with_sep(tt, ',');
|
let pound = quote! {@PUNCT '#'};
|
||||||
|
let mut tt = tt.clone();
|
||||||
let expand_error =
|
tt.delimiter.kind = tt::DelimiterKind::Parenthesis;
|
||||||
ExpandResult::new(tt::Subtree::empty(), mbe::ExpandError::NoMatchingRule.into());
|
return ExpandResult::ok(quote! {
|
||||||
|
builtin #pound format_args #tt
|
||||||
let mut key_args = FxHashMap::default();
|
|
||||||
let mut args = args.into_iter().filter_map(|mut arg| {
|
|
||||||
// Remove `key =`.
|
|
||||||
if matches!(arg.token_trees.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=')
|
|
||||||
{
|
|
||||||
// but not with `==`
|
|
||||||
if !matches!(arg.token_trees.get(2), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=')
|
|
||||||
{
|
|
||||||
let key = arg.token_trees.drain(..2).next().unwrap();
|
|
||||||
key_args.insert(key.to_string(), arg);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(arg)
|
|
||||||
}).collect::<Vec<_>>().into_iter();
|
|
||||||
// ^^^^^^^ we need this collect, to enforce the side effect of the filter_map closure (building the `key_args`)
|
|
||||||
let Some(format_subtree) = args.next() else {
|
|
||||||
return expand_error;
|
|
||||||
};
|
|
||||||
let format_string = (|| {
|
|
||||||
let token_tree = format_subtree.token_trees.get(0)?;
|
|
||||||
match token_tree {
|
|
||||||
tt::TokenTree::Leaf(l) => match l {
|
|
||||||
tt::Leaf::Literal(l) => {
|
|
||||||
if let Some(mut text) = l.text.strip_prefix('r') {
|
|
||||||
let mut raw_sharps = String::new();
|
|
||||||
while let Some(t) = text.strip_prefix('#') {
|
|
||||||
text = t;
|
|
||||||
raw_sharps.push('#');
|
|
||||||
}
|
|
||||||
text =
|
|
||||||
text.strip_suffix(&raw_sharps)?.strip_prefix('"')?.strip_suffix('"')?;
|
|
||||||
Some((text, l.span, Some(raw_sharps)))
|
|
||||||
} else {
|
|
||||||
let text = l.text.strip_prefix('"')?.strip_suffix('"')?;
|
|
||||||
let span = l.span;
|
|
||||||
Some((text, span, None))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
tt::TokenTree::Subtree(_) => None,
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
let Some((format_string, _format_string_span, raw_sharps)) = format_string else {
|
|
||||||
return expand_error;
|
|
||||||
};
|
|
||||||
let mut format_iter = format_string.chars().peekable();
|
|
||||||
let mut parts = vec![];
|
|
||||||
let mut last_part = String::new();
|
|
||||||
let mut arg_tts = vec![];
|
|
||||||
let mut err = None;
|
|
||||||
while let Some(c) = format_iter.next() {
|
|
||||||
// Parsing the format string. See https://doc.rust-lang.org/std/fmt/index.html#syntax for the grammar and more info
|
|
||||||
match c {
|
|
||||||
'{' => {
|
|
||||||
if format_iter.peek() == Some(&'{') {
|
|
||||||
format_iter.next();
|
|
||||||
last_part.push('{');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mut argument = String::new();
|
|
||||||
while ![Some(&'}'), Some(&':')].contains(&format_iter.peek()) {
|
|
||||||
argument.push(match format_iter.next() {
|
|
||||||
Some(c) => c,
|
|
||||||
None => return expand_error,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
let format_spec = match format_iter.next().unwrap() {
|
|
||||||
'}' => "".to_owned(),
|
|
||||||
':' => {
|
|
||||||
let mut s = String::new();
|
|
||||||
while let Some(c) = format_iter.next() {
|
|
||||||
if c == '}' {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s.push(c);
|
|
||||||
}
|
|
||||||
s
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
parts.push(mem::take(&mut last_part));
|
|
||||||
let arg_tree = if argument.is_empty() {
|
|
||||||
match args.next() {
|
|
||||||
Some(it) => it,
|
|
||||||
None => {
|
|
||||||
err = Some(mbe::ExpandError::NoMatchingRule.into());
|
|
||||||
tt::Subtree::empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let Some(tree) = key_args.get(&argument) {
|
|
||||||
tree.clone()
|
|
||||||
} else {
|
|
||||||
// FIXME: we should pick the related substring of the `_format_string_span` as the span. You
|
|
||||||
// can use `.char_indices()` instead of `.char()` for `format_iter` to find the substring interval.
|
|
||||||
let ident = Ident::new(argument, tt::TokenId::unspecified());
|
|
||||||
quote!(#ident)
|
|
||||||
};
|
|
||||||
let formatter = match &*format_spec {
|
|
||||||
"?" => quote!(::core::fmt::Debug::fmt),
|
|
||||||
"" => quote!(::core::fmt::Display::fmt),
|
|
||||||
_ => {
|
|
||||||
// FIXME: implement the rest and return expand error here
|
|
||||||
quote!(::core::fmt::Display::fmt)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
arg_tts.push(quote! { ::core::fmt::ArgumentV1::new(&(#arg_tree), #formatter), });
|
|
||||||
}
|
|
||||||
'}' => {
|
|
||||||
if format_iter.peek() == Some(&'}') {
|
|
||||||
format_iter.next();
|
|
||||||
last_part.push('}');
|
|
||||||
} else {
|
|
||||||
return expand_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => last_part.push(c),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_part += end_string;
|
|
||||||
if !last_part.is_empty() {
|
|
||||||
parts.push(last_part);
|
|
||||||
}
|
|
||||||
let part_tts = parts.into_iter().map(|it| {
|
|
||||||
let text = if let Some(raw) = &raw_sharps {
|
|
||||||
format!("r{raw}\"{}\"{raw}", it).into()
|
|
||||||
} else {
|
|
||||||
format!("\"{}\"", it).into()
|
|
||||||
};
|
|
||||||
let l = tt::Literal { span: tt::TokenId::unspecified(), text };
|
|
||||||
quote!(#l ,)
|
|
||||||
});
|
});
|
||||||
let arg_tts = arg_tts.into_iter().flat_map(|arg| arg.token_trees);
|
|
||||||
let expanded = quote! {
|
|
||||||
::core::fmt::Arguments::new_v1(&[##part_tts], &[##arg_tts])
|
|
||||||
};
|
|
||||||
ExpandResult { value: expanded, err }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn asm_expand(
|
fn asm_expand(
|
||||||
|
@ -399,8 +259,6 @@ fn asm_expand(
|
||||||
_id: MacroCallId,
|
_id: MacroCallId,
|
||||||
tt: &tt::Subtree,
|
tt: &tt::Subtree,
|
||||||
) -> ExpandResult<tt::Subtree> {
|
) -> ExpandResult<tt::Subtree> {
|
||||||
// FIXME: parse asm here
|
|
||||||
|
|
||||||
// We expand all assembly snippets to `format_args!` invocations to get format syntax
|
// We expand all assembly snippets to `format_args!` invocations to get format syntax
|
||||||
// highlighting for them.
|
// highlighting for them.
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,12 @@ impl Name {
|
||||||
Name(Repr::Text(text))
|
Name(Repr::Text(text))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: See above, unfortunately some places really need this right now
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub const fn new_text_dont_use(text: SmolStr) -> Name {
|
||||||
|
Name(Repr::Text(text))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_tuple_field(idx: usize) -> Name {
|
pub fn new_tuple_field(idx: usize) -> Name {
|
||||||
Name(Repr::TupleField(idx))
|
Name(Repr::TupleField(idx))
|
||||||
}
|
}
|
||||||
|
@ -302,6 +308,16 @@ pub mod known {
|
||||||
rust_2018,
|
rust_2018,
|
||||||
rust_2021,
|
rust_2021,
|
||||||
v1,
|
v1,
|
||||||
|
new_display,
|
||||||
|
new_debug,
|
||||||
|
new_lower_exp,
|
||||||
|
new_upper_exp,
|
||||||
|
new_octal,
|
||||||
|
new_pointer,
|
||||||
|
new_binary,
|
||||||
|
new_lower_hex,
|
||||||
|
new_upper_hex,
|
||||||
|
from_usize,
|
||||||
// Components of known path (type name)
|
// Components of known path (type name)
|
||||||
Iterator,
|
Iterator,
|
||||||
IntoIterator,
|
IntoIterator,
|
||||||
|
@ -327,6 +343,13 @@ pub mod known {
|
||||||
Not,
|
Not,
|
||||||
None,
|
None,
|
||||||
Index,
|
Index,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Center,
|
||||||
|
Unknown,
|
||||||
|
Is,
|
||||||
|
Param,
|
||||||
|
Implied,
|
||||||
// Components of known path (function name)
|
// Components of known path (function name)
|
||||||
filter_map,
|
filter_map,
|
||||||
next,
|
next,
|
||||||
|
@ -335,6 +358,8 @@ pub mod known {
|
||||||
is_empty,
|
is_empty,
|
||||||
as_str,
|
as_str,
|
||||||
new,
|
new,
|
||||||
|
new_v1_formatted,
|
||||||
|
none,
|
||||||
// Builtin macros
|
// Builtin macros
|
||||||
asm,
|
asm,
|
||||||
assert,
|
assert,
|
||||||
|
|
|
@ -178,13 +178,30 @@ impl InferenceContext<'_> {
|
||||||
remaining_index: usize,
|
remaining_index: usize,
|
||||||
id: ExprOrPatId,
|
id: ExprOrPatId,
|
||||||
) -> Option<(ValueNs, Substitution)> {
|
) -> Option<(ValueNs, Substitution)> {
|
||||||
assert!(remaining_index < path.segments().len());
|
|
||||||
// there may be more intermediate segments between the resolved one and
|
// there may be more intermediate segments between the resolved one and
|
||||||
// the end. Only the last segment needs to be resolved to a value; from
|
// the end. Only the last segment needs to be resolved to a value; from
|
||||||
// the segments before that, we need to get either a type or a trait ref.
|
// the segments before that, we need to get either a type or a trait ref.
|
||||||
|
|
||||||
let resolved_segment = path.segments().get(remaining_index - 1).unwrap();
|
let _d;
|
||||||
let remaining_segments = path.segments().skip(remaining_index);
|
let (resolved_segment, remaining_segments) = match path {
|
||||||
|
Path::Normal { .. } => {
|
||||||
|
assert!(remaining_index < path.segments().len());
|
||||||
|
(
|
||||||
|
path.segments().get(remaining_index - 1).unwrap(),
|
||||||
|
path.segments().skip(remaining_index),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Path::LangItem(..) => (
|
||||||
|
PathSegment {
|
||||||
|
name: {
|
||||||
|
_d = hir_expand::name::known::Unknown;
|
||||||
|
&_d
|
||||||
|
},
|
||||||
|
args_and_bindings: None,
|
||||||
|
},
|
||||||
|
path.segments(),
|
||||||
|
),
|
||||||
|
};
|
||||||
let is_before_last = remaining_segments.len() == 1;
|
let is_before_last = remaining_segments.len() == 1;
|
||||||
|
|
||||||
match (def, is_before_last) {
|
match (def, is_before_last) {
|
||||||
|
|
|
@ -3612,3 +3612,18 @@ fn main() {
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builtin_format_args() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- minicore: fmt
|
||||||
|
fn main() {
|
||||||
|
let are = "are";
|
||||||
|
let count = 10;
|
||||||
|
builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
|
||||||
|
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'_>
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -15,26 +15,13 @@ use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
|
||||||
// Move an expression out of a format string.
|
// Move an expression out of a format string.
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
// macro_rules! format_args {
|
// # //- minicore: fmt
|
||||||
// ($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
// }
|
|
||||||
// macro_rules! print {
|
|
||||||
// ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn main() {
|
// fn main() {
|
||||||
// print!("{var} {x + 1}$0");
|
// print!("{var} {x + 1}$0");
|
||||||
// }
|
// }
|
||||||
// ```
|
// ```
|
||||||
// ->
|
// ->
|
||||||
// ```
|
// ```
|
||||||
// macro_rules! format_args {
|
|
||||||
// ($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
// }
|
|
||||||
// macro_rules! print {
|
|
||||||
// ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn main() {
|
// fn main() {
|
||||||
// print!("{var} {}"$0, x + 1);
|
// print!("{var} {}"$0, x + 1);
|
||||||
// }
|
// }
|
||||||
|
@ -158,37 +145,21 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::tests::check_assist;
|
use crate::tests::check_assist;
|
||||||
|
|
||||||
const MACRO_DECL: &'static str = r#"
|
|
||||||
macro_rules! format_args {
|
|
||||||
($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
}
|
|
||||||
macro_rules! print {
|
|
||||||
($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
fn add_macro_decl(s: &'static str) -> String {
|
|
||||||
MACRO_DECL.to_string() + s
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn multiple_middle_arg() {
|
fn multiple_middle_arg() {
|
||||||
check_assist(
|
check_assist(
|
||||||
extract_expressions_from_format_string,
|
extract_expressions_from_format_string,
|
||||||
&add_macro_decl(
|
r#"
|
||||||
r#"
|
//- minicore: fmt
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{} {x + 1:b} {}$0", y + 2, 2);
|
print!("{} {x + 1:b} {}$0", y + 2, 2);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
r#"
|
||||||
&add_macro_decl(
|
|
||||||
r#"
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{} {:b} {}"$0, y + 2, x + 1, 2);
|
print!("{} {:b} {}"$0, y + 2, x + 1, 2);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,20 +167,17 @@ fn main() {
|
||||||
fn single_arg() {
|
fn single_arg() {
|
||||||
check_assist(
|
check_assist(
|
||||||
extract_expressions_from_format_string,
|
extract_expressions_from_format_string,
|
||||||
&add_macro_decl(
|
r#"
|
||||||
r#"
|
//- minicore: fmt
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{obj.value:b}$0",);
|
print!("{obj.value:b}$0",);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
r#"
|
||||||
&add_macro_decl(
|
|
||||||
r#"
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{:b}"$0, obj.value);
|
print!("{:b}"$0, obj.value);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,20 +185,17 @@ fn main() {
|
||||||
fn multiple_middle_placeholders_arg() {
|
fn multiple_middle_placeholders_arg() {
|
||||||
check_assist(
|
check_assist(
|
||||||
extract_expressions_from_format_string,
|
extract_expressions_from_format_string,
|
||||||
&add_macro_decl(
|
r#"
|
||||||
r#"
|
//- minicore: fmt
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{} {x + 1:b} {} {}$0", y + 2, 2);
|
print!("{} {x + 1:b} {} {}$0", y + 2, 2);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
r#"
|
||||||
&add_macro_decl(
|
|
||||||
r#"
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{} {:b} {} {}"$0, y + 2, x + 1, 2, $1);
|
print!("{} {:b} {} {}"$0, y + 2, x + 1, 2, $1);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -238,20 +203,17 @@ fn main() {
|
||||||
fn multiple_trailing_args() {
|
fn multiple_trailing_args() {
|
||||||
check_assist(
|
check_assist(
|
||||||
extract_expressions_from_format_string,
|
extract_expressions_from_format_string,
|
||||||
&add_macro_decl(
|
r#"
|
||||||
r#"
|
//- minicore: fmt
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{:b} {x + 1:b} {Struct(1, 2)}$0", 1);
|
print!("{:b} {x + 1:b} {Struct(1, 2)}$0", 1);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
r#"
|
||||||
&add_macro_decl(
|
|
||||||
r#"
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{:b} {:b} {}"$0, 1, x + 1, Struct(1, 2));
|
print!("{:b} {:b} {}"$0, 1, x + 1, Struct(1, 2));
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,20 +221,17 @@ fn main() {
|
||||||
fn improper_commas() {
|
fn improper_commas() {
|
||||||
check_assist(
|
check_assist(
|
||||||
extract_expressions_from_format_string,
|
extract_expressions_from_format_string,
|
||||||
&add_macro_decl(
|
r#"
|
||||||
r#"
|
//- minicore: fmt
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{} {x + 1:b} {Struct(1, 2)}$0", 1,);
|
print!("{} {x + 1:b} {Struct(1, 2)}$0", 1,);
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
r#"
|
||||||
&add_macro_decl(
|
|
||||||
r#"
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
|
print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,20 +239,17 @@ fn main() {
|
||||||
fn nested_tt() {
|
fn nested_tt() {
|
||||||
check_assist(
|
check_assist(
|
||||||
extract_expressions_from_format_string,
|
extract_expressions_from_format_string,
|
||||||
&add_macro_decl(
|
r#"
|
||||||
r#"
|
//- minicore: fmt
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("My name is {} {x$0 + x}", stringify!(Paperino))
|
print!("My name is {} {x$0 + x}", stringify!(Paperino))
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
r#"
|
||||||
&add_macro_decl(
|
|
||||||
r#"
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("My name is {} {}"$0, stringify!(Paperino), x + x)
|
print!("My name is {} {}"$0, stringify!(Paperino), x + x)
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,22 +257,19 @@ fn main() {
|
||||||
fn extract_only_expressions() {
|
fn extract_only_expressions() {
|
||||||
check_assist(
|
check_assist(
|
||||||
extract_expressions_from_format_string,
|
extract_expressions_from_format_string,
|
||||||
&add_macro_decl(
|
r#"
|
||||||
r#"
|
//- minicore: fmt
|
||||||
fn main() {
|
fn main() {
|
||||||
let var = 1 + 1;
|
let var = 1 + 1;
|
||||||
print!("foobar {var} {var:?} {x$0 + x}")
|
print!("foobar {var} {var:?} {x$0 + x}")
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
r#"
|
||||||
&add_macro_decl(
|
|
||||||
r#"
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let var = 1 + 1;
|
let var = 1 + 1;
|
||||||
print!("foobar {var} {var:?} {}"$0, x + x)
|
print!("foobar {var} {var:?} {}"$0, x + x)
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -694,25 +694,12 @@ fn doctest_extract_expressions_from_format_string() {
|
||||||
check_doc_test(
|
check_doc_test(
|
||||||
"extract_expressions_from_format_string",
|
"extract_expressions_from_format_string",
|
||||||
r#####"
|
r#####"
|
||||||
macro_rules! format_args {
|
//- minicore: fmt
|
||||||
($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
}
|
|
||||||
macro_rules! print {
|
|
||||||
($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{var} {x + 1}$0");
|
print!("{var} {x + 1}$0");
|
||||||
}
|
}
|
||||||
"#####,
|
"#####,
|
||||||
r#####"
|
r#####"
|
||||||
macro_rules! format_args {
|
|
||||||
($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
}
|
|
||||||
macro_rules! print {
|
|
||||||
($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
print!("{var} {}"$0, x + 1);
|
print!("{var} {}"$0, x + 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,9 +51,7 @@ mod tests {
|
||||||
fn works_when_wrapped() {
|
fn works_when_wrapped() {
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
macro_rules! format_args {
|
//- minicore: fmt
|
||||||
($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
}
|
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
|
($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
|
||||||
}
|
}
|
||||||
|
@ -70,9 +68,7 @@ fn main() {
|
||||||
fn no_completion_without_brace() {
|
fn no_completion_without_brace() {
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
macro_rules! format_args {
|
//- minicore: fmt
|
||||||
($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
}
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let foobar = 1;
|
let foobar = 1;
|
||||||
format_args!("f$0");
|
format_args!("f$0");
|
||||||
|
@ -87,18 +83,13 @@ fn main() {
|
||||||
check_edit(
|
check_edit(
|
||||||
"foobar",
|
"foobar",
|
||||||
r#"
|
r#"
|
||||||
macro_rules! format_args {
|
//- minicore: fmt
|
||||||
($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
}
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let foobar = 1;
|
let foobar = 1;
|
||||||
format_args!("{f$0");
|
format_args!("{f$0");
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
macro_rules! format_args {
|
|
||||||
($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
}
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let foobar = 1;
|
let foobar = 1;
|
||||||
format_args!("{foobar");
|
format_args!("{foobar");
|
||||||
|
@ -108,18 +99,13 @@ fn main() {
|
||||||
check_edit(
|
check_edit(
|
||||||
"foobar",
|
"foobar",
|
||||||
r#"
|
r#"
|
||||||
macro_rules! format_args {
|
//- minicore: fmt
|
||||||
($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
}
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let foobar = 1;
|
let foobar = 1;
|
||||||
format_args!("{$0");
|
format_args!("{$0");
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
r#"
|
r#"
|
||||||
macro_rules! format_args {
|
|
||||||
($lit:literal $(tt:tt)*) => { 0 },
|
|
||||||
}
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let foobar = 1;
|
let foobar = 1;
|
||||||
format_args!("{foobar");
|
format_args!("{foobar");
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
//! Tools to work with format string literals for the `format_args!` family of macros.
|
//! Tools to work with format string literals for the `format_args!` family of macros.
|
||||||
use crate::syntax_helpers::node_ext::macro_call_for_string_token;
|
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{self, IsString},
|
ast::{self, IsString},
|
||||||
TextRange, TextSize,
|
AstNode, AstToken, TextRange, TextSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME: This can probably be re-implemented via the HIR?
|
||||||
pub fn is_format_string(string: &ast::String) -> bool {
|
pub fn is_format_string(string: &ast::String) -> bool {
|
||||||
// Check if `string` is a format string argument of a macro invocation.
|
// Check if `string` is a format string argument of a macro invocation.
|
||||||
// `string` is a string literal, mapped down into the innermost macro expansion.
|
// `string` is a string literal, mapped down into the innermost macro expansion.
|
||||||
|
@ -15,19 +15,9 @@ pub fn is_format_string(string: &ast::String) -> bool {
|
||||||
// This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
|
// This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
|
||||||
// strings. It still fails for `concat!("{", "}")`, but that is rare.
|
// strings. It still fails for `concat!("{", "}")`, but that is rare.
|
||||||
(|| {
|
(|| {
|
||||||
let name = macro_call_for_string_token(string)?.path()?.segment()?.name_ref()?;
|
let lit = string.syntax().parent().and_then(ast::Literal::cast)?;
|
||||||
|
let fa = lit.syntax().parent().and_then(ast::FormatArgsExpr::cast)?;
|
||||||
if !matches!(
|
(fa.template()? == ast::Expr::Literal(lit)).then_some(|| ())
|
||||||
name.text().as_str(),
|
|
||||||
"format_args" | "format_args_nl" | "const_format_args" | "panic_2015" | "panic_2021"
|
|
||||||
) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NB: we match against `panic_2015`/`panic_2021` here because they have a special-cased arm for
|
|
||||||
// `"{}"`, which otherwise wouldn't get highlighted.
|
|
||||||
|
|
||||||
Some(())
|
|
||||||
})()
|
})()
|
||||||
.is_some()
|
.is_some()
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,7 @@ struct S;
|
||||||
fn macro_diag_builtin() {
|
fn macro_diag_builtin() {
|
||||||
check_diagnostics(
|
check_diagnostics(
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: fmt
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! env {}
|
macro_rules! env {}
|
||||||
|
|
||||||
|
@ -166,9 +167,6 @@ macro_rules! include {}
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
macro_rules! compile_error {}
|
macro_rules! compile_error {}
|
||||||
|
|
||||||
#[rustc_builtin_macro]
|
|
||||||
macro_rules! format_args { () => {} }
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Test a handful of built-in (eager) macros:
|
// Test a handful of built-in (eager) macros:
|
||||||
|
|
||||||
|
@ -189,7 +187,7 @@ fn main() {
|
||||||
// Lazy:
|
// Lazy:
|
||||||
|
|
||||||
format_args!();
|
format_args!();
|
||||||
//^^^^^^^^^^^ error: no rule matches input tokens
|
//^^^^^^^^^^^ error: Syntax Error in Expansion: expected expression
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
|
@ -6574,3 +6574,23 @@ fn test() {
|
||||||
"#]],
|
"#]],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_args_arg() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
//- minicore: fmt
|
||||||
|
fn test() {
|
||||||
|
let foo = 0;
|
||||||
|
format_args!("{}", foo$0);
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*foo*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let foo: i32 // size = 4, align = 4
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -474,7 +474,7 @@ fn main() {
|
||||||
file_id: FileId(
|
file_id: FileId(
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
range: 9289..9297,
|
range: 10739..10747,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
tooltip: "",
|
tooltip: "",
|
||||||
|
@ -487,7 +487,7 @@ fn main() {
|
||||||
file_id: FileId(
|
file_id: FileId(
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
range: 9321..9325,
|
range: 10771..10775,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
tooltip: "",
|
tooltip: "",
|
||||||
|
@ -511,7 +511,7 @@ fn main() {
|
||||||
file_id: FileId(
|
file_id: FileId(
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
range: 9289..9297,
|
range: 10739..10747,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
tooltip: "",
|
tooltip: "",
|
||||||
|
@ -524,7 +524,7 @@ fn main() {
|
||||||
file_id: FileId(
|
file_id: FileId(
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
range: 9321..9325,
|
range: 10771..10775,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
tooltip: "",
|
tooltip: "",
|
||||||
|
@ -548,7 +548,7 @@ fn main() {
|
||||||
file_id: FileId(
|
file_id: FileId(
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
range: 9289..9297,
|
range: 10739..10747,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
tooltip: "",
|
tooltip: "",
|
||||||
|
@ -561,7 +561,7 @@ fn main() {
|
||||||
file_id: FileId(
|
file_id: FileId(
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
range: 9321..9325,
|
range: 10771..10775,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
tooltip: "",
|
tooltip: "",
|
||||||
|
|
|
@ -17,6 +17,7 @@ pub(super) fn highlight_format_string(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Replace this with the HIR info we have now.
|
||||||
lex_format_specifiers(string, &mut |piece_range, kind| {
|
lex_format_specifiers(string, &mut |piece_range, kind| {
|
||||||
if let Some(highlight) = highlight_format_specifier(kind) {
|
if let Some(highlight) = highlight_format_specifier(kind) {
|
||||||
stack.add(HlRange {
|
stack.add(HlRange {
|
||||||
|
|
|
@ -617,6 +617,7 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
|
||||||
CONST => SymbolKind::Const,
|
CONST => SymbolKind::Const,
|
||||||
STATIC => SymbolKind::Static,
|
STATIC => SymbolKind::Static,
|
||||||
IDENT_PAT => SymbolKind::Local,
|
IDENT_PAT => SymbolKind::Local,
|
||||||
|
FORMAT_ARGS_ARG => SymbolKind::Local,
|
||||||
_ => return default.into(),
|
_ => return default.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,17 +45,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
</style>
|
</style>
|
||||||
<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
|
<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
|
||||||
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="brace">{</span>
|
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="brace">{</span>
|
||||||
<span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
<span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
||||||
<span class="brace">}</span><span class="parenthesis">)</span>
|
<span class="brace">}</span><span class="parenthesis">)</span>
|
||||||
<span class="brace">}</span>
|
<span class="brace">}</span>
|
||||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
|
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
|
||||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
|
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
|
||||||
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args</span> <span class="brace">{</span><span class="brace">}</span>
|
|
||||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
|
|
||||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
|
|
||||||
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">const_format_args</span> <span class="brace">{</span><span class="brace">}</span>
|
|
||||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">rustc_builtin_macro</span><span class="attribute_bracket attribute">]</span>
|
|
||||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">macro_export</span><span class="attribute_bracket attribute">]</span>
|
|
||||||
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span><span class="brace">}</span>
|
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">format_args_nl</span> <span class="brace">{</span><span class="brace">}</span>
|
||||||
|
|
||||||
<span class="keyword">mod</span> <span class="module declaration">panic</span> <span class="brace">{</span>
|
<span class="keyword">mod</span> <span class="module declaration">panic</span> <span class="brace">{</span>
|
||||||
|
@ -75,7 +69,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_display<span class="parenthesis">(</span><span class="punctuation">&</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span>
|
<span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_display<span class="parenthesis">(</span><span class="punctuation">&</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span>
|
||||||
<span class="parenthesis">)</span><span class="comma">,</span>
|
<span class="parenthesis">)</span><span class="comma">,</span>
|
||||||
<span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span>
|
<span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="colon">:</span>expr<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span>
|
||||||
<span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_fmt<span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>const_format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
|
<span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panicking<span class="colon">:</span><span class="colon">:</span>panic_fmt<span class="parenthesis">(</span>const_format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>fmt<span class="comma">,</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
|
||||||
<span class="parenthesis">)</span><span class="comma">,</span>
|
<span class="parenthesis">)</span><span class="comma">,</span>
|
||||||
<span class="brace">}</span>
|
<span class="brace">}</span>
|
||||||
<span class="brace">}</span>
|
<span class="brace">}</span>
|
||||||
|
@ -92,7 +86,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
|
|
||||||
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span>
|
<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span>
|
||||||
<span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
<span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
||||||
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
|
||||||
<span class="brace">}</span>
|
<span class="brace">}</span>
|
||||||
|
|
||||||
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
||||||
|
@ -114,18 +108,18 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello, world!"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello, world!"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "The number is 1"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "The number is 1"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "(3, 4)"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "(3, 4)"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "4"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "4"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "1 2"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "1 2"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">42</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "0042" with leading zerosV</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">42</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "0042" with leading zerosV</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1 1 2"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1 1 2"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "test"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "test"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="none macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="none macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="none macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "a 3 b"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="variable declaration macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="variable declaration macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "a 3 b"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "{2}"</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "{2}"</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="none macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
|
@ -140,10 +134,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="none macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="none macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="variable declaration macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="none macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="none macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="none macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
|
|
||||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{}"</span>
|
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{}"</span>
|
||||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{{}}"</span><span class="semicolon">;</span>
|
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{{}}"</span><span class="semicolon">;</span>
|
||||||
|
@ -167,24 +161,24 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
||||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">c"</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\xFF</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, valid unicodes</span>
|
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">c"</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\xFF</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, valid unicodes</span>
|
||||||
<span class="keyword">let</span> <span class="variable declaration reference">backslash</span> <span class="operator">=</span> <span class="string_literal">r"\\"</span><span class="semicolon">;</span>
|
<span class="keyword">let</span> <span class="variable declaration reference">backslash</span> <span class="operator">=</span> <span class="string_literal">r"\\"</span><span class="semicolon">;</span>
|
||||||
|
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
|
|
||||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more {}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{} asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
|
<span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
|
||||||
<span class="keyword">let</span> <span class="variable declaration">o</span><span class="colon">:</span> <span class="builtin_type">u64</span><span class="semicolon">;</span>
|
<span class="keyword">let</span> <span class="variable declaration">o</span><span class="colon">:</span> <span class="builtin_type">u64</span><span class="semicolon">;</span>
|
||||||
<span class="macro unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>
|
<span class="macro unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>
|
||||||
<span class="string_literal macro">"mov </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">, </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span>
|
<span class="string_literal macro">"mov {0}, {1}"</span><span class="comma macro">,</span>
|
||||||
<span class="string_literal macro">"add </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro">, 5"</span><span class="comma macro">,</span>
|
<span class="string_literal macro">"add {0}, 5"</span><span class="comma macro">,</span>
|
||||||
<span class="none macro">out</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">o</span><span class="comma macro">,</span>
|
<span class="none macro">out</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">o</span><span class="comma macro">,</span>
|
||||||
<span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">i</span><span class="comma macro">,</span>
|
<span class="keyword control macro">in</span><span class="parenthesis macro">(</span><span class="none macro">reg</span><span class="parenthesis macro">)</span> <span class="none macro">i</span><span class="comma macro">,</span>
|
||||||
<span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
|
|
||||||
<span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">concat</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="macro">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="none macro">format_args</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="none macro">toho</span><span class="punctuation macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
<span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="macro default_library library macro">format_args</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="macro macro">toho</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||||
<span class="brace">}</span></code></pre>
|
<span class="brace">}</span></code></pre>
|
|
@ -401,19 +401,14 @@ fn test_string_highlighting() {
|
||||||
// thus, we have to copy the macro definition from `std`
|
// thus, we have to copy the macro definition from `std`
|
||||||
check_highlighting(
|
check_highlighting(
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: fmt
|
||||||
macro_rules! println {
|
macro_rules! println {
|
||||||
($($arg:tt)*) => ({
|
($($arg:tt)*) => ({
|
||||||
$crate::io::_print($crate::format_args_nl!($($arg)*));
|
$crate::io::_print(format_args_nl!($($arg)*));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
#[rustc_builtin_macro]
|
#[rustc_builtin_macro]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! format_args {}
|
|
||||||
#[rustc_builtin_macro]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! const_format_args {}
|
|
||||||
#[rustc_builtin_macro]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! format_args_nl {}
|
macro_rules! format_args_nl {}
|
||||||
|
|
||||||
mod panic {
|
mod panic {
|
||||||
|
@ -433,7 +428,7 @@ mod panic {
|
||||||
$crate::panicking::panic_display(&$arg)
|
$crate::panicking::panic_display(&$arg)
|
||||||
),
|
),
|
||||||
($fmt:expr, $($arg:tt)+) => (
|
($fmt:expr, $($arg:tt)+) => (
|
||||||
$crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+))
|
$crate::panicking::panic_fmt(const_format_args!($fmt, $($arg)+))
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,7 +445,7 @@ macro_rules! concat {}
|
||||||
|
|
||||||
macro_rules! toho {
|
macro_rules! toho {
|
||||||
() => ($crate::panic!("not yet implemented"));
|
() => ($crate::panic!("not yet implemented"));
|
||||||
($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", $crate::format_args!($($arg)+)));
|
($($arg:tt)+) => ($crate::panic!("not yet implemented: {}", format_args!($($arg)+)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -219,7 +219,7 @@ fn tuple_expr(p: &mut Parser<'_>) -> CompletedMarker {
|
||||||
// test builtin_expr
|
// test builtin_expr
|
||||||
// fn foo() {
|
// fn foo() {
|
||||||
// builtin#asm(0);
|
// builtin#asm(0);
|
||||||
// builtin#format_args(0);
|
// builtin#format_args("", 0, 1, a = 2 + 3, a + b);
|
||||||
// builtin#offset_of(Foo, bar.baz.0);
|
// builtin#offset_of(Foo, bar.baz.0);
|
||||||
// }
|
// }
|
||||||
fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
|
fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
|
||||||
|
@ -249,6 +249,24 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
|
||||||
p.bump_remap(T![format_args]);
|
p.bump_remap(T![format_args]);
|
||||||
p.expect(T!['(']);
|
p.expect(T!['(']);
|
||||||
expr(p);
|
expr(p);
|
||||||
|
if p.eat(T![,]) {
|
||||||
|
while !p.at(EOF) && !p.at(T![')']) {
|
||||||
|
let m = p.start();
|
||||||
|
if p.at(IDENT) && p.nth_at(1, T![=]) {
|
||||||
|
name(p);
|
||||||
|
p.bump(T![=]);
|
||||||
|
}
|
||||||
|
if expr(p).is_none() {
|
||||||
|
m.abandon(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m.complete(p, FORMAT_ARGS_ARG);
|
||||||
|
|
||||||
|
if !p.at(T![')']) {
|
||||||
|
p.expect(T![,]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
p.expect(T![')']);
|
p.expect(T![')']);
|
||||||
Some(m.complete(p, FORMAT_ARGS_EXPR))
|
Some(m.complete(p, FORMAT_ARGS_EXPR))
|
||||||
} else if p.at_contextual_kw(T![asm]) {
|
} else if p.at_contextual_kw(T![asm]) {
|
||||||
|
|
|
@ -210,6 +210,7 @@ pub enum SyntaxKind {
|
||||||
OFFSET_OF_EXPR,
|
OFFSET_OF_EXPR,
|
||||||
ASM_EXPR,
|
ASM_EXPR,
|
||||||
FORMAT_ARGS_EXPR,
|
FORMAT_ARGS_EXPR,
|
||||||
|
FORMAT_ARGS_ARG,
|
||||||
CALL_EXPR,
|
CALL_EXPR,
|
||||||
INDEX_EXPR,
|
INDEX_EXPR,
|
||||||
METHOD_CALL_EXPR,
|
METHOD_CALL_EXPR,
|
||||||
|
|
|
@ -30,7 +30,50 @@ SOURCE_FILE
|
||||||
FORMAT_ARGS_KW "format_args"
|
FORMAT_ARGS_KW "format_args"
|
||||||
L_PAREN "("
|
L_PAREN "("
|
||||||
LITERAL
|
LITERAL
|
||||||
INT_NUMBER "0"
|
STRING "\"\""
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE " "
|
||||||
|
FORMAT_ARGS_ARG
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "0"
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE " "
|
||||||
|
FORMAT_ARGS_ARG
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "1"
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE " "
|
||||||
|
FORMAT_ARGS_ARG
|
||||||
|
NAME
|
||||||
|
IDENT "a"
|
||||||
|
WHITESPACE " "
|
||||||
|
EQ "="
|
||||||
|
WHITESPACE " "
|
||||||
|
BIN_EXPR
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "2"
|
||||||
|
WHITESPACE " "
|
||||||
|
PLUS "+"
|
||||||
|
WHITESPACE " "
|
||||||
|
LITERAL
|
||||||
|
INT_NUMBER "3"
|
||||||
|
COMMA ","
|
||||||
|
WHITESPACE " "
|
||||||
|
FORMAT_ARGS_ARG
|
||||||
|
BIN_EXPR
|
||||||
|
PATH_EXPR
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "a"
|
||||||
|
WHITESPACE " "
|
||||||
|
PLUS "+"
|
||||||
|
WHITESPACE " "
|
||||||
|
PATH_EXPR
|
||||||
|
PATH
|
||||||
|
PATH_SEGMENT
|
||||||
|
NAME_REF
|
||||||
|
IDENT "b"
|
||||||
R_PAREN ")"
|
R_PAREN ")"
|
||||||
SEMICOLON ";"
|
SEMICOLON ";"
|
||||||
WHITESPACE "\n "
|
WHITESPACE "\n "
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
fn foo() {
|
fn foo() {
|
||||||
builtin#asm(0);
|
builtin#asm(0);
|
||||||
builtin#format_args(0);
|
builtin#format_args("", 0, 1, a = 2 + 3, a + b);
|
||||||
builtin#offset_of(Foo, bar.baz.0);
|
builtin#offset_of(Foo, bar.baz.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -382,7 +382,13 @@ AsmExpr =
|
||||||
Attr* 'builtin' '#' 'asm' '(' Expr ')'
|
Attr* 'builtin' '#' 'asm' '(' Expr ')'
|
||||||
|
|
||||||
FormatArgsExpr =
|
FormatArgsExpr =
|
||||||
Attr* 'builtin' '#' 'format_args' '(' ')'
|
Attr* 'builtin' '#' 'format_args' '('
|
||||||
|
template:Expr
|
||||||
|
(',' args:(FormatArgsArg (',' FormatArgsArg)* ','?)? )?
|
||||||
|
')'
|
||||||
|
|
||||||
|
FormatArgsArg =
|
||||||
|
(Name '=')? Expr
|
||||||
|
|
||||||
MacroExpr =
|
MacroExpr =
|
||||||
MacroCall
|
MacroCall
|
||||||
|
|
|
@ -931,6 +931,9 @@ impl FormatArgsExpr {
|
||||||
support::token(&self.syntax, T![format_args])
|
support::token(&self.syntax, T![format_args])
|
||||||
}
|
}
|
||||||
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
|
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
|
||||||
|
pub fn template(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
|
pub fn comma_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![,]) }
|
||||||
|
pub fn args(&self) -> AstChildren<FormatArgsArg> { support::children(&self.syntax) }
|
||||||
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1163,6 +1166,16 @@ impl UnderscoreExpr {
|
||||||
pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
|
pub fn underscore_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![_]) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct FormatArgsArg {
|
||||||
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
}
|
||||||
|
impl ast::HasName for FormatArgsArg {}
|
||||||
|
impl FormatArgsArg {
|
||||||
|
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
|
||||||
|
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct StmtList {
|
pub struct StmtList {
|
||||||
pub(crate) syntax: SyntaxNode,
|
pub(crate) syntax: SyntaxNode,
|
||||||
|
@ -2855,6 +2868,17 @@ impl AstNode for UnderscoreExpr {
|
||||||
}
|
}
|
||||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
}
|
}
|
||||||
|
impl AstNode for FormatArgsArg {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG }
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if Self::can_cast(syntax.kind()) {
|
||||||
|
Some(Self { syntax })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||||
|
}
|
||||||
impl AstNode for StmtList {
|
impl AstNode for StmtList {
|
||||||
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
|
fn can_cast(kind: SyntaxKind) -> bool { kind == STMT_LIST }
|
||||||
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
@ -4254,6 +4278,7 @@ impl AstNode for AnyHasName {
|
||||||
| VARIANT
|
| VARIANT
|
||||||
| CONST_PARAM
|
| CONST_PARAM
|
||||||
| TYPE_PARAM
|
| TYPE_PARAM
|
||||||
|
| FORMAT_ARGS_ARG
|
||||||
| IDENT_PAT
|
| IDENT_PAT
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -4860,6 +4885,11 @@ impl std::fmt::Display for UnderscoreExpr {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl std::fmt::Display for FormatArgsArg {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
impl std::fmt::Display for StmtList {
|
impl std::fmt::Display for StmtList {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
std::fmt::Display::fmt(self.syntax(), f)
|
std::fmt::Display::fmt(self.syntax(), f)
|
||||||
|
|
|
@ -169,6 +169,7 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
|
||||||
"OFFSET_OF_EXPR",
|
"OFFSET_OF_EXPR",
|
||||||
"ASM_EXPR",
|
"ASM_EXPR",
|
||||||
"FORMAT_ARGS_EXPR",
|
"FORMAT_ARGS_EXPR",
|
||||||
|
"FORMAT_ARGS_ARG",
|
||||||
// postfix
|
// postfix
|
||||||
"CALL_EXPR",
|
"CALL_EXPR",
|
||||||
"INDEX_EXPR",
|
"INDEX_EXPR",
|
||||||
|
|
|
@ -899,32 +899,90 @@ pub mod fmt {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result;
|
fn fmt(&self, f: &mut Formatter<'_>) -> Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
mod rt {
|
||||||
type Opaque;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[lang = "format_argument"]
|
extern "C" {
|
||||||
pub struct Argument<'a> {
|
type Opaque;
|
||||||
value: &'a Opaque,
|
}
|
||||||
formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Argument<'a> {
|
#[lang = "format_argument"]
|
||||||
pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {
|
pub struct Argument<'a> {
|
||||||
use crate::mem::transmute;
|
value: &'a Opaque,
|
||||||
unsafe { Argument { formatter: transmute(f), value: transmute(x) } }
|
formatter: fn(&Opaque, &mut Formatter<'_>) -> Result,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Argument<'a> {
|
||||||
|
pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'b> {
|
||||||
|
use crate::mem::transmute;
|
||||||
|
unsafe { Argument { formatter: transmute(f), value: transmute(x) } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[lang = "format_alignment"]
|
||||||
|
pub enum Alignment {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Center,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[lang = "format_count"]
|
||||||
|
pub enum Count {
|
||||||
|
Is(usize),
|
||||||
|
Param(usize),
|
||||||
|
Implied,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[lang = "format_placeholder"]
|
||||||
|
pub struct Placeholder {
|
||||||
|
pub position: usize,
|
||||||
|
pub fill: char,
|
||||||
|
pub align: Alignment,
|
||||||
|
pub flags: u32,
|
||||||
|
pub precision: Count,
|
||||||
|
pub width: Count,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Placeholder {
|
||||||
|
pub const fn new(
|
||||||
|
position: usize,
|
||||||
|
fill: char,
|
||||||
|
align: Alignment,
|
||||||
|
flags: u32,
|
||||||
|
precision: Count,
|
||||||
|
width: Count,
|
||||||
|
) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[lang = "format_unsafe_arg"]
|
||||||
|
pub struct UnsafeArg {
|
||||||
|
_private: (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnsafeArg {
|
||||||
|
pub unsafe fn new() -> Self;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[lang = "format_arguments"]
|
#[lang = "format_arguments"]
|
||||||
pub struct Arguments<'a> {
|
pub struct Arguments<'a> {
|
||||||
pieces: &'a [&'static str],
|
pieces: &'a [&'static str],
|
||||||
args: &'a [Argument<'a>],
|
fmt: Option<&'a [rt::Placeholder]>,
|
||||||
|
args: &'a [rt::Argument<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Arguments<'a> {
|
impl<'a> Arguments<'a> {
|
||||||
pub const fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> {
|
pub const fn new_v1(pieces: &'a [&'static str], args: &'a [Argument<'a>]) -> Arguments<'a> {
|
||||||
Arguments { pieces, args }
|
Arguments { pieces, fmt: None, args }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_v1_formatted(
|
||||||
|
pieces: &'a [&'static str],
|
||||||
|
args: &'a [rt::Argument<'a>],
|
||||||
|
fmt: &'a [rt::Placeholder],
|
||||||
|
_unsafe_arg: rt::UnsafeArg,
|
||||||
|
) -> Arguments<'a> {
|
||||||
|
Arguments { pieces, fmt: Some(fmt), args }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1294,8 +1352,6 @@ mod macros {
|
||||||
/* compiler built-in */
|
/* compiler built-in */
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) use panic;
|
|
||||||
// endregion:panic
|
// endregion:panic
|
||||||
|
|
||||||
// region:fmt
|
// region:fmt
|
||||||
|
@ -1306,7 +1362,20 @@ mod macros {
|
||||||
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
|
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) use const_format_args;
|
#[macro_export]
|
||||||
|
#[rustc_builtin_macro]
|
||||||
|
macro_rules! format_args {
|
||||||
|
($fmt:expr) => {{ /* compiler built-in */ }};
|
||||||
|
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => {{
|
||||||
|
$crate::io::_print($crate::format_args!($($arg)*));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
// endregion:fmt
|
// endregion:fmt
|
||||||
|
|
||||||
// region:derive
|
// region:derive
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue