auto merge of #9919 : alexcrichton/rust/fmt-begone, r=huonw
It lived a good life, but its time has come. The groundwork is set for the official transition after the next snapshot (removal of XXX2 macros)
This commit is contained in:
commit
cd623e3e36
18 changed files with 26 additions and 1533 deletions
|
|
@ -222,7 +222,7 @@ pub fn syntax_expander_table() -> SyntaxEnv {
|
|||
span: None,
|
||||
} as @SyntaxExpanderTTItemTrait,
|
||||
None)));
|
||||
syntax_expanders.insert(intern(&"oldfmt"),
|
||||
syntax_expanders.insert(intern(&"fmt"),
|
||||
builtin_normal_tt_no_ctxt(
|
||||
ext::fmt::expand_syntax_ext));
|
||||
syntax_expanders.insert(intern(&"format_args"),
|
||||
|
|
|
|||
|
|
@ -809,51 +809,7 @@ pub fn std_macros() -> @str {
|
|||
|
||||
macro_rules! ignore (($($x:tt)*) => (()))
|
||||
|
||||
#[cfg(not(nofmt))]
|
||||
mod fmt_extension {
|
||||
#[macro_escape];
|
||||
|
||||
macro_rules! fmt(($($arg:tt)*) => (oldfmt!($($arg)*)))
|
||||
|
||||
macro_rules! log(
|
||||
($lvl:expr, $arg:expr) => ({
|
||||
let lvl = $lvl;
|
||||
if lvl <= __log_level() {
|
||||
format_args!(|args| {
|
||||
::std::logging::log(lvl, args)
|
||||
}, \"{}\", fmt!(\"%?\", $arg))
|
||||
}
|
||||
});
|
||||
($lvl:expr, $($arg:expr),+) => ({
|
||||
let lvl = $lvl;
|
||||
if lvl <= __log_level() {
|
||||
format_args!(|args| {
|
||||
::std::logging::log(lvl, args)
|
||||
}, \"{}\", fmt!($($arg),+))
|
||||
}
|
||||
})
|
||||
)
|
||||
macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) )
|
||||
macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) )
|
||||
macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) )
|
||||
macro_rules! debug( ($($arg:tt)*) => (
|
||||
if cfg!(not(ndebug)) { log!(4u32, $($arg)*) }
|
||||
))
|
||||
|
||||
macro_rules! fail(
|
||||
() => (
|
||||
fail2!(\"explicit failure\")
|
||||
);
|
||||
($msg:expr) => (
|
||||
::std::sys::FailWithCause::fail_with($msg, file!(), line!())
|
||||
);
|
||||
($( $arg:expr ),+) => (
|
||||
::std::sys::FailWithCause::fail_with(fmt!( $($arg),+ ), file!(), line!())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
macro_rules! log2(
|
||||
macro_rules! log(
|
||||
($lvl:expr, $($arg:tt)+) => ({
|
||||
let lvl = $lvl;
|
||||
if lvl <= __log_level() {
|
||||
|
|
@ -863,16 +819,16 @@ pub fn std_macros() -> @str {
|
|||
}
|
||||
})
|
||||
)
|
||||
macro_rules! error2( ($($arg:tt)*) => (log2!(1u32, $($arg)*)) )
|
||||
macro_rules! warn2 ( ($($arg:tt)*) => (log2!(2u32, $($arg)*)) )
|
||||
macro_rules! info2 ( ($($arg:tt)*) => (log2!(3u32, $($arg)*)) )
|
||||
macro_rules! debug2( ($($arg:tt)*) => (
|
||||
if cfg!(not(ndebug)) { log2!(4u32, $($arg)*) }
|
||||
macro_rules! error( ($($arg:tt)*) => (log!(1u32, $($arg)*)) )
|
||||
macro_rules! warn ( ($($arg:tt)*) => (log!(2u32, $($arg)*)) )
|
||||
macro_rules! info ( ($($arg:tt)*) => (log!(3u32, $($arg)*)) )
|
||||
macro_rules! debug( ($($arg:tt)*) => (
|
||||
if cfg!(not(ndebug)) { log!(4u32, $($arg)*) }
|
||||
))
|
||||
|
||||
macro_rules! fail2(
|
||||
macro_rules! fail(
|
||||
() => (
|
||||
fail2!(\"explicit failure\")
|
||||
fail!(\"explicit failure\")
|
||||
);
|
||||
($fmt:expr) => (
|
||||
::std::sys::FailWithCause::fail_with($fmt, file!(), line!())
|
||||
|
|
@ -882,6 +838,14 @@ pub fn std_macros() -> @str {
|
|||
)
|
||||
)
|
||||
|
||||
// NOTE (acrichto): remove these after the next snapshot
|
||||
macro_rules! log2( ($($arg:tt)*) => (log!($($arg)*)) )
|
||||
macro_rules! error2( ($($arg:tt)*) => (error!($($arg)*)) )
|
||||
macro_rules! warn2 ( ($($arg:tt)*) => (warn!($($arg)*)) )
|
||||
macro_rules! info2 ( ($($arg:tt)*) => (info!($($arg)*)) )
|
||||
macro_rules! debug2( ($($arg:tt)*) => (debug!($($arg)*)) )
|
||||
macro_rules! fail2( ($($arg:tt)*) => (fail!($($arg)*)) )
|
||||
|
||||
macro_rules! assert(
|
||||
($cond:expr) => {
|
||||
if !$cond {
|
||||
|
|
|
|||
|
|
@ -8,320 +8,19 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
* The compiler code necessary to support the fmt! extension. Eventually this
|
||||
* should all get sucked into either the standard library extfmt module or the
|
||||
* compiler syntax extension plugin interface.
|
||||
*/
|
||||
/// Deprecated fmt! syntax extension
|
||||
|
||||
use ast;
|
||||
use codemap::Span;
|
||||
use ext::base::*;
|
||||
use ext::base;
|
||||
use ext::build::AstBuilder;
|
||||
|
||||
use std::option;
|
||||
use std::unstable::extfmt::ct::*;
|
||||
use parse::token::{str_to_ident};
|
||||
pub fn expand_syntax_ext(ecx: @base::ExtCtxt, sp: Span,
|
||||
_tts: &[ast::token_tree]) -> base::MacResult {
|
||||
ecx.span_err(sp, "`fmt!` is deprecated, use `format!` instead");
|
||||
ecx.parse_sess.span_diagnostic.span_note(sp,
|
||||
"see http://static.rust-lang.org/doc/master/std/fmt/index.html \
|
||||
for documentation");
|
||||
|
||||
pub fn expand_syntax_ext(cx: @ExtCtxt, sp: Span, tts: &[ast::token_tree])
|
||||
-> base::MacResult {
|
||||
let args = get_exprs_from_tts(cx, sp, tts);
|
||||
if args.len() == 0 {
|
||||
cx.span_fatal(sp, "fmt! takes at least 1 argument.");
|
||||
}
|
||||
let (fmt, _fmt_str_style) =
|
||||
expr_to_str(cx, args[0],
|
||||
"first argument to fmt! must be a string literal.");
|
||||
let fmtspan = args[0].span;
|
||||
debug2!("Format string: {}", fmt);
|
||||
fn parse_fmt_err_(cx: @ExtCtxt, sp: Span, msg: &str) -> ! {
|
||||
cx.span_fatal(sp, msg);
|
||||
}
|
||||
let parse_fmt_err: &fn(&str) -> ! = |s| parse_fmt_err_(cx, fmtspan, s);
|
||||
let pieces = parse_fmt_string(fmt, parse_fmt_err);
|
||||
MRExpr(pieces_to_expr(cx, sp, pieces, args))
|
||||
}
|
||||
|
||||
// FIXME (#2249): A lot of these functions for producing expressions can
|
||||
// probably be factored out in common with other code that builds
|
||||
// expressions. Also: Cleanup the naming of these functions.
|
||||
// Note: Moved many of the common ones to build.rs --kevina
|
||||
fn pieces_to_expr(cx: @ExtCtxt, sp: Span,
|
||||
pieces: ~[Piece], args: ~[@ast::Expr])
|
||||
-> @ast::Expr {
|
||||
fn make_path_vec(ident: &str) -> ~[ast::Ident] {
|
||||
return ~[str_to_ident("std"),
|
||||
str_to_ident("unstable"),
|
||||
str_to_ident("extfmt"),
|
||||
str_to_ident("rt"),
|
||||
str_to_ident(ident)];
|
||||
}
|
||||
fn make_rt_path_expr(cx: @ExtCtxt, sp: Span, nm: &str) -> @ast::Expr {
|
||||
let path = make_path_vec(nm);
|
||||
cx.expr_path(cx.path_global(sp, path))
|
||||
}
|
||||
// Produces an AST expression that represents a RT::conv record,
|
||||
// which tells the RT::conv* functions how to perform the conversion
|
||||
|
||||
fn make_rt_conv_expr(cx: @ExtCtxt, sp: Span, cnv: &Conv) -> @ast::Expr {
|
||||
fn make_flags(cx: @ExtCtxt, sp: Span, flags: &[Flag]) -> @ast::Expr {
|
||||
let mut tmp_expr = make_rt_path_expr(cx, sp, "flag_none");
|
||||
for f in flags.iter() {
|
||||
let fstr = match *f {
|
||||
FlagLeftJustify => "flag_left_justify",
|
||||
FlagLeftZeroPad => "flag_left_zero_pad",
|
||||
FlagSpaceForSign => "flag_space_for_sign",
|
||||
FlagSignAlways => "flag_sign_always",
|
||||
FlagAlternate => "flag_alternate"
|
||||
};
|
||||
tmp_expr = cx.expr_binary(sp, ast::BiBitOr, tmp_expr,
|
||||
make_rt_path_expr(cx, sp, fstr));
|
||||
}
|
||||
return tmp_expr;
|
||||
}
|
||||
fn make_count(cx: @ExtCtxt, sp: Span, cnt: Count) -> @ast::Expr {
|
||||
match cnt {
|
||||
CountImplied => {
|
||||
return make_rt_path_expr(cx, sp, "CountImplied");
|
||||
}
|
||||
CountIs(c) => {
|
||||
let count_lit = cx.expr_uint(sp, c as uint);
|
||||
let count_is_path = make_path_vec("CountIs");
|
||||
let count_is_args = ~[count_lit];
|
||||
return cx.expr_call_global(sp, count_is_path, count_is_args);
|
||||
}
|
||||
_ => cx.span_unimpl(sp, "unimplemented fmt! conversion")
|
||||
}
|
||||
}
|
||||
fn make_ty(cx: @ExtCtxt, sp: Span, t: Ty) -> @ast::Expr {
|
||||
let rt_type = match t {
|
||||
TyHex(c) => match c {
|
||||
CaseUpper => "TyHexUpper",
|
||||
CaseLower => "TyHexLower"
|
||||
},
|
||||
TyBits => "TyBits",
|
||||
TyOctal => "TyOctal",
|
||||
_ => "TyDefault"
|
||||
};
|
||||
return make_rt_path_expr(cx, sp, rt_type);
|
||||
}
|
||||
fn make_conv_struct(cx: @ExtCtxt, sp: Span, flags_expr: @ast::Expr,
|
||||
width_expr: @ast::Expr, precision_expr: @ast::Expr,
|
||||
ty_expr: @ast::Expr) -> @ast::Expr {
|
||||
cx.expr_struct(
|
||||
sp,
|
||||
cx.path_global(sp, make_path_vec("Conv")),
|
||||
~[
|
||||
cx.field_imm(sp, str_to_ident("flags"), flags_expr),
|
||||
cx.field_imm(sp, str_to_ident("width"), width_expr),
|
||||
cx.field_imm(sp, str_to_ident("precision"), precision_expr),
|
||||
cx.field_imm(sp, str_to_ident("ty"), ty_expr)
|
||||
]
|
||||
)
|
||||
}
|
||||
let rt_conv_flags = make_flags(cx, sp, cnv.flags);
|
||||
let rt_conv_width = make_count(cx, sp, cnv.width);
|
||||
let rt_conv_precision = make_count(cx, sp, cnv.precision);
|
||||
let rt_conv_ty = make_ty(cx, sp, cnv.ty);
|
||||
make_conv_struct(cx, sp, rt_conv_flags, rt_conv_width,
|
||||
rt_conv_precision, rt_conv_ty)
|
||||
}
|
||||
fn make_conv_call(cx: @ExtCtxt, sp: Span, conv_type: &str, cnv: &Conv,
|
||||
arg: @ast::Expr, buf: @ast::Expr) -> @ast::Expr {
|
||||
let fname = ~"conv_" + conv_type;
|
||||
let path = make_path_vec(fname);
|
||||
let cnv_expr = make_rt_conv_expr(cx, sp, cnv);
|
||||
let args = ~[cnv_expr, arg, buf];
|
||||
cx.expr_call_global(arg.span, path, args)
|
||||
}
|
||||
|
||||
fn make_new_conv(cx: @ExtCtxt, sp: Span, cnv: &Conv,
|
||||
arg: @ast::Expr, buf: @ast::Expr) -> @ast::Expr {
|
||||
fn is_signed_type(cnv: &Conv) -> bool {
|
||||
match cnv.ty {
|
||||
TyInt(s) => match s {
|
||||
Signed => return true,
|
||||
Unsigned => return false
|
||||
},
|
||||
TyFloat => return true,
|
||||
_ => return false
|
||||
}
|
||||
}
|
||||
let unsupported = ~"conversion not supported in fmt! string";
|
||||
match cnv.param {
|
||||
option::None => (),
|
||||
_ => cx.span_unimpl(sp, unsupported)
|
||||
}
|
||||
for f in cnv.flags.iter() {
|
||||
match *f {
|
||||
FlagLeftJustify => (),
|
||||
FlagSignAlways => {
|
||||
if !is_signed_type(cnv) {
|
||||
cx.span_fatal(sp,
|
||||
"+ flag only valid in \
|
||||
signed fmt! conversion");
|
||||
}
|
||||
}
|
||||
FlagSpaceForSign => {
|
||||
if !is_signed_type(cnv) {
|
||||
cx.span_fatal(sp,
|
||||
"space flag only valid in \
|
||||
signed fmt! conversions");
|
||||
}
|
||||
}
|
||||
FlagLeftZeroPad => (),
|
||||
_ => cx.span_unimpl(sp, unsupported)
|
||||
}
|
||||
}
|
||||
match cnv.width {
|
||||
CountImplied => (),
|
||||
CountIs(_) => (),
|
||||
_ => cx.span_unimpl(sp, unsupported)
|
||||
}
|
||||
match cnv.precision {
|
||||
CountImplied => (),
|
||||
CountIs(_) => (),
|
||||
_ => cx.span_unimpl(sp, unsupported)
|
||||
}
|
||||
let (name, actual_arg) = match cnv.ty {
|
||||
TyStr => ("str", arg),
|
||||
TyInt(Signed) => ("int", arg),
|
||||
TyBool => ("bool", arg),
|
||||
TyChar => ("char", arg),
|
||||
TyBits | TyOctal | TyHex(_) | TyInt(Unsigned) => ("uint", arg),
|
||||
TyFloat => ("float", arg),
|
||||
TyPointer => ("pointer", arg),
|
||||
TyPoly => ("poly", cx.expr_addr_of(sp, arg))
|
||||
};
|
||||
return make_conv_call(cx, arg.span, name, cnv, actual_arg,
|
||||
cx.expr_mut_addr_of(arg.span, buf));
|
||||
}
|
||||
fn log_conv(c: &Conv) {
|
||||
debug2!("Building conversion:");
|
||||
match c.param {
|
||||
Some(p) => { debug2!("param: {}", p.to_str()); }
|
||||
_ => debug2!("param: none")
|
||||
}
|
||||
for f in c.flags.iter() {
|
||||
match *f {
|
||||
FlagLeftJustify => debug2!("flag: left justify"),
|
||||
FlagLeftZeroPad => debug2!("flag: left zero pad"),
|
||||
FlagSpaceForSign => debug2!("flag: left space pad"),
|
||||
FlagSignAlways => debug2!("flag: sign always"),
|
||||
FlagAlternate => debug2!("flag: alternate")
|
||||
}
|
||||
}
|
||||
match c.width {
|
||||
CountIs(i) =>
|
||||
debug2!("width: count is {}", i.to_str()),
|
||||
CountIsParam(i) =>
|
||||
debug2!("width: count is param {}", i.to_str()),
|
||||
CountIsNextParam => debug2!("width: count is next param"),
|
||||
CountImplied => debug2!("width: count is implied")
|
||||
}
|
||||
match c.precision {
|
||||
CountIs(i) =>
|
||||
debug2!("prec: count is {}", i.to_str()),
|
||||
CountIsParam(i) =>
|
||||
debug2!("prec: count is param {}", i.to_str()),
|
||||
CountIsNextParam => debug2!("prec: count is next param"),
|
||||
CountImplied => debug2!("prec: count is implied")
|
||||
}
|
||||
match c.ty {
|
||||
TyBool => debug2!("type: bool"),
|
||||
TyStr => debug2!("type: str"),
|
||||
TyChar => debug2!("type: char"),
|
||||
TyInt(s) => match s {
|
||||
Signed => debug2!("type: signed"),
|
||||
Unsigned => debug2!("type: unsigned")
|
||||
},
|
||||
TyBits => debug2!("type: bits"),
|
||||
TyHex(cs) => match cs {
|
||||
CaseUpper => debug2!("type: uhex"),
|
||||
CaseLower => debug2!("type: lhex"),
|
||||
},
|
||||
TyOctal => debug2!("type: octal"),
|
||||
TyFloat => debug2!("type: float"),
|
||||
TyPointer => debug2!("type: pointer"),
|
||||
TyPoly => debug2!("type: poly")
|
||||
}
|
||||
}
|
||||
|
||||
/* Short circuit an easy case up front (won't work otherwise) */
|
||||
if pieces.len() == 0 {
|
||||
return cx.expr_str_uniq(args[0].span, @"");
|
||||
}
|
||||
|
||||
let fmt_sp = args[0].span;
|
||||
let mut n = 0u;
|
||||
let nargs = args.len();
|
||||
|
||||
/* 'ident' is the local buffer building up the result of fmt! */
|
||||
let ident = str_to_ident("__fmtbuf");
|
||||
let buf = || cx.expr_ident(fmt_sp, ident);
|
||||
let core_ident = str_to_ident("std");
|
||||
let str_ident = str_to_ident("str");
|
||||
let push_ident = str_to_ident("push_str");
|
||||
let mut stms = ~[];
|
||||
|
||||
/* Translate each piece (portion of the fmt expression) by invoking the
|
||||
corresponding function in std::unstable::extfmt. Each function takes a
|
||||
buffer to insert data into along with the data being formatted. */
|
||||
let npieces = pieces.len();
|
||||
for (i, pc) in pieces.move_iter().enumerate() {
|
||||
match pc {
|
||||
/* Raw strings get appended via str::push_str */
|
||||
PieceString(s) => {
|
||||
/* If this is the first portion, then initialize the local
|
||||
buffer with it directly. If it's actually the only piece,
|
||||
then there's no need for it to be mutable */
|
||||
if i == 0 {
|
||||
stms.push(cx.stmt_let(fmt_sp, npieces > 1,
|
||||
ident, cx.expr_str_uniq(fmt_sp, s.to_managed())));
|
||||
} else {
|
||||
// we call the push_str function because the
|
||||
// bootstrap doesnt't seem to work if we call the
|
||||
// method.
|
||||
let args = ~[cx.expr_mut_addr_of(fmt_sp, buf()),
|
||||
cx.expr_str(fmt_sp, s.to_managed())];
|
||||
let call = cx.expr_call_global(fmt_sp,
|
||||
~[core_ident,
|
||||
str_ident,
|
||||
push_ident],
|
||||
args);
|
||||
stms.push(cx.stmt_expr(call));
|
||||
}
|
||||
}
|
||||
|
||||
/* Invoke the correct conv function in extfmt */
|
||||
PieceConv(ref conv) => {
|
||||
n += 1u;
|
||||
if n >= nargs {
|
||||
cx.span_fatal(sp,
|
||||
"not enough arguments to fmt! \
|
||||
for the given format string");
|
||||
}
|
||||
|
||||
log_conv(conv);
|
||||
/* If the first portion is a conversion, then the local buffer
|
||||
must be initialized as an empty string */
|
||||
if i == 0 {
|
||||
stms.push(cx.stmt_let(fmt_sp, true, ident,
|
||||
cx.expr_str_uniq(fmt_sp, @"")));
|
||||
}
|
||||
stms.push(cx.stmt_expr(make_new_conv(cx, fmt_sp, conv,
|
||||
args[n], buf())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let expected_nargs = n + 1u; // n conversions + the fmt string
|
||||
if expected_nargs < nargs {
|
||||
cx.span_fatal
|
||||
(sp, format!("too many arguments to fmt!. found {}, expected {}",
|
||||
nargs, expected_nargs));
|
||||
}
|
||||
|
||||
cx.expr_block(cx.block(fmt_sp, stms, Some(buf())))
|
||||
base::MRExpr(ecx.expr_uint(sp, 2))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue