diff options
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ext/base.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/ext/ifmt.rs | 167 |
2 files changed, 108 insertions, 61 deletions
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 48a13646686..284801ab123 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -161,6 +161,8 @@ pub fn syntax_expander_table() -> SyntaxEnv { builtin_normal_tt_no_ctxt(ext::ifmt::expand_write)); syntax_expanders.insert(intern(&"writeln"), builtin_normal_tt_no_ctxt(ext::ifmt::expand_writeln)); + syntax_expanders.insert(intern(&"format_args"), + builtin_normal_tt_no_ctxt(ext::ifmt::expand_format_args)); syntax_expanders.insert( intern(&"auto_encode"), @SE(ItemDecorator(ext::auto_encode::expand_auto_encode))); diff --git a/src/libsyntax/ext/ifmt.rs b/src/libsyntax/ext/ifmt.rs index 486069db4f0..2f040ef2519 100644 --- a/src/libsyntax/ext/ifmt.rs +++ b/src/libsyntax/ext/ifmt.rs @@ -60,7 +60,7 @@ impl Context { let p = rsparse::new_parser_from_tts(self.ecx.parse_sess(), self.ecx.cfg(), tts.to_owned()); - // If we want a leading expression (for ifmtf), parse it here + // If we want a leading expression, parse it here let extra = if leading_expr { let e = Some(p.parse_expr()); if !p.eat(&token::COMMA) { @@ -341,12 +341,18 @@ impl Context { ~[self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), self.ecx.ident_of("parse"), self.ecx.ident_of(s)] }; - let none = || { - let p = self.ecx.path(sp, ~[self.ecx.ident_of("None")]); - self.ecx.expr_path(p) - }; + let none = self.ecx.path_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("option"), + self.ecx.ident_of("None")]); + let none = self.ecx.expr_path(none); let some = |e: @ast::Expr| { - self.ecx.expr_call_ident(sp, self.ecx.ident_of("Some"), ~[e]) + let p = self.ecx.path_global(sp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("option"), + self.ecx.ident_of("Some")]); + let p = self.ecx.expr_path(p); + self.ecx.expr_call(sp, p, ~[e]) }; let trans_count = |c: parse::Count| { match c { @@ -397,7 +403,7 @@ impl Context { parse::Plural(offset, ref arms, ref default) => { let offset = match offset { Some(i) => { some(self.ecx.expr_uint(sp, i)) } - None => { none() } + None => { none.clone() } }; let arms = arms.iter().map(|arm| { let p = self.ecx.path_global(sp, rtpath("PluralArm")); @@ -522,7 +528,7 @@ impl Context { // Translate the method (if any) let method = match arg.method { - None => { none() } + None => { none.clone() } Some(ref m) => { let m = trans_method(*m); some(self.ecx.expr_addr_of(sp, m)) @@ -541,7 +547,7 @@ impl Context { /// Actually builds the expression which the ifmt! block will be expanded /// to - fn to_expr(&self, extra: Option<@ast::Expr>, f: &str) -> @ast::Expr { + fn to_expr(&self, extra: Option<@ast::Expr>, f: Option<&str>) -> @ast::Expr { let mut lets = ~[]; let mut locals = ~[]; let mut names = vec::from_fn(self.name_positions.len(), |_| None); @@ -556,21 +562,19 @@ impl Context { // Next, build up the static array which will become our precompiled // format "string" let fmt = self.ecx.expr_vec(self.fmtsp, self.pieces.clone()); + let piece_ty = self.ecx.ty_path(self.ecx.path_all( + self.fmtsp, + true, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("rt"), + self.ecx.ident_of("Piece"), + ], + Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), + ~[] + ), None); let ty = ast::ty_fixed_length_vec( - self.ecx.ty_mt( - self.ecx.ty_path(self.ecx.path_all( - self.fmtsp, - true, ~[ - self.ecx.ident_of("std"), - self.ecx.ident_of("fmt"), - self.ecx.ident_of("rt"), - self.ecx.ident_of("Piece"), - ], - Some(self.ecx.lifetime(self.fmtsp, self.ecx.ident_of("static"))), - ~[] - ), None), - ast::MutImmutable - ), + self.ecx.ty_mt(piece_ty.clone(), ast::MutImmutable), self.ecx.expr_uint(self.fmtsp, self.pieces.len()) ); let ty = self.ecx.ty(self.fmtsp, ty); @@ -596,7 +600,8 @@ impl Context { let name = self.ecx.ident_of(fmt!("__arg%u", i)); let e = self.ecx.expr_addr_of(e.span, e); lets.push(self.ecx.stmt_let(e.span, false, name, e)); - locals.push(self.format_arg(e.span, Left(i), name)); + locals.push(self.format_arg(e.span, Left(i), + self.ecx.expr_ident(e.span, name))); } for (&name, &e) in self.names.iter() { if !self.name_types.contains_key(&name) { loop } @@ -605,48 +610,83 @@ impl Context { let e = self.ecx.expr_addr_of(e.span, e); lets.push(self.ecx.stmt_let(e.span, false, lname, e)); names[*self.name_positions.get(&name)] = - Some(self.format_arg(e.span, Right(name), lname)); + Some(self.format_arg(e.span, Right(name), + self.ecx.expr_ident(e.span, lname))); } let args = names.move_iter().map(|a| a.unwrap()); let mut args = locals.move_iter().chain(args); - let mut fmt_args = match extra { - Some(e) => ~[e], None => ~[] - }; - fmt_args.push(self.ecx.expr_ident(self.fmtsp, static_name)); - fmt_args.push(self.ecx.expr_vec(self.fmtsp, args.collect())); + let result = match f { + // Invocation of write!()/format!(), call the function and we're + // done. + Some(f) => { + let mut fmt_args = match extra { + Some(e) => ~[e], None => ~[] + }; + fmt_args.push(self.ecx.expr_ident(self.fmtsp, static_name)); + fmt_args.push(self.ecx.expr_vec_slice(self.fmtsp, + args.collect())); - // Next, build up the actual call to the {s,f}printf function. - let result = self.ecx.expr_call_global(self.fmtsp, ~[ - self.ecx.ident_of("std"), - self.ecx.ident_of("fmt"), - self.ecx.ident_of(f), - ], fmt_args); - - // sprintf is unsafe, but we just went through a lot of work to - // validate that our call is save, so inject the unsafe block for the - // user. - let result = self.ecx.expr_block(ast::Block { - view_items: ~[], - stmts: ~[], - expr: Some(result), - id: ast::DUMMY_NODE_ID, - rules: ast::UnsafeBlock(ast::CompilerGenerated), - span: self.fmtsp, - }); - - self.ecx.expr_block(self.ecx.block(self.fmtsp, lets, Some(result))) + let result = self.ecx.expr_call_global(self.fmtsp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of(f), + ], fmt_args); + + // sprintf is unsafe, but we just went through a lot of work to + // validate that our call is save, so inject the unsafe block + // for the user. + self.ecx.expr_block(ast::Block { + view_items: ~[], + stmts: ~[], + expr: Some(result), + id: ast::DUMMY_NODE_ID, + rules: ast::UnsafeBlock(ast::CompilerGenerated), + span: self.fmtsp, + }) + } + + // Invocation of format_args!() + None => { + let fmt = self.ecx.expr_ident(self.fmtsp, static_name); + let args = self.ecx.expr_vec_slice(self.fmtsp, args.collect()); + let result = self.ecx.expr_call_global(self.fmtsp, ~[ + self.ecx.ident_of("std"), + self.ecx.ident_of("fmt"), + self.ecx.ident_of("Arguments"), + self.ecx.ident_of("new"), + ], ~[fmt, args]); + + // We did all the work of making sure that the arguments + // structure is safe, so we can safely have an unsafe block. + let result = self.ecx.expr_block(ast::Block { + view_items: ~[], + stmts: ~[], + expr: Some(result), + id: ast::DUMMY_NODE_ID, + rules: ast::UnsafeBlock(ast::CompilerGenerated), + span: self.fmtsp, + }); + let extra = extra.unwrap(); + let resname = self.ecx.ident_of("__args"); + lets.push(self.ecx.stmt_let(self.fmtsp, false, resname, result)); + let res = self.ecx.expr_ident(self.fmtsp, resname); + self.ecx.expr_call(extra.span, extra, ~[ + self.ecx.expr_addr_of(extra.span, res)]) + } + }; + self.ecx.expr_block(self.ecx.block(self.fmtsp, lets, + Some(result))) } - fn format_arg(&self, sp: Span, arg: Either<uint, @str>, - ident: ast::Ident) -> @ast::Expr { - let ty = match arg { + fn format_arg(&self, sp: Span, argno: Either<uint, @str>, + arg: @ast::Expr) -> @ast::Expr { + let ty = match argno { Left(i) => self.arg_types[i].unwrap(), Right(s) => *self.name_types.get(&s) }; - let argptr = self.ecx.expr_ident(sp, ident); let fmt_trait = match ty { Unknown => "Default", Known(tyname) => { @@ -675,14 +715,14 @@ impl Context { self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), self.ecx.ident_of("argumentstr"), - ], ~[argptr]) + ], ~[arg]) } Unsigned => { return self.ecx.expr_call_global(sp, ~[ self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), self.ecx.ident_of("argumentuint"), - ], ~[argptr]) + ], ~[arg]) } }; @@ -696,28 +736,33 @@ impl Context { self.ecx.ident_of("std"), self.ecx.ident_of("fmt"), self.ecx.ident_of("argument"), - ], ~[self.ecx.expr_path(format_fn), argptr]) + ], ~[self.ecx.expr_path(format_fn), arg]) } } pub fn expand_format(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> base::MacResult { - expand_ifmt(ecx, sp, tts, false, false, "format") + expand_ifmt(ecx, sp, tts, false, false, Some("format_unsafe")) } pub fn expand_write(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> base::MacResult { - expand_ifmt(ecx, sp, tts, true, false, "write") + expand_ifmt(ecx, sp, tts, true, false, Some("write_unsafe")) } pub fn expand_writeln(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree]) -> base::MacResult { - expand_ifmt(ecx, sp, tts, true, true, "write") + expand_ifmt(ecx, sp, tts, true, true, Some("write_unsafe")) +} + +pub fn expand_format_args(ecx: @ExtCtxt, sp: Span, + tts: &[ast::token_tree]) -> base::MacResult { + expand_ifmt(ecx, sp, tts, true, false, None) } fn expand_ifmt(ecx: @ExtCtxt, sp: Span, tts: &[ast::token_tree], leading_arg: bool, append_newline: bool, - function: &str) -> base::MacResult { + function: Option<&str>) -> base::MacResult { let mut cx = Context { ecx: ecx, args: ~[], |
