Skip to content

Commit 80487dd

Browse files
committed
std: Extract format string parsing out of libstd
This code does not belong in libstd, and rather belongs in a dedicated crate. In the future, the syntax::ext::format module should move to the fmt_macros crate (hence the name of the crate), but for now the fmt_macros crate will only contain the format string parser. The entire fmt_macros crate is marked #[experimental] because it is not meant for general consumption, only the format!() interface is officially supported, not the internals. This is a breaking change for anyone using the internals of std::fmt::parse. Some of the flags have moved to std::fmt::rt, while the actual parsing support has all moved to the fmt_macros library. [breaking-change]
1 parent 87115fd commit 80487dd

File tree

6 files changed

+100
-48
lines changed

6 files changed

+100
-48
lines changed

mk/crates.mk

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
TARGET_CRATES := libc std green rustuv native flate arena glob term semver \
5353
uuid serialize sync getopts collections num test time rand \
5454
workcache url log regex graphviz core
55-
HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros
55+
HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros fmt_macros
5656
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
5757
TOOLS := compiletest rustdoc rustc
5858

@@ -61,7 +61,7 @@ DEPS_std := core libc native:rustrt native:compiler-rt native:backtrace
6161
DEPS_green := std rand native:context_switch
6262
DEPS_rustuv := std native:uv native:uv_support
6363
DEPS_native := std
64-
DEPS_syntax := std term serialize collections log
64+
DEPS_syntax := std term serialize collections log fmt_macros
6565
DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \
6666
collections time log
6767
DEPS_rustdoc := rustc native:hoedown serialize sync getopts collections \
@@ -88,6 +88,7 @@ DEPS_workcache := std serialize collections log
8888
DEPS_log := std sync
8989
DEPS_regex := std collections
9090
DEPS_regex_macros = syntax std regex
91+
DEPS_fmt_macros = std
9192

9293
TOOL_DEPS_compiletest := test green rustuv getopts
9394
TOOL_DEPS_rustdoc := rustdoc native

src/libstd/fmt/parse.rs renamed to src/libfmt_macros/lib.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,21 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! Parsing of format strings
11+
//! Macro support for format strings
1212
//!
1313
//! These structures are used when parsing format strings for the compiler.
1414
//! Parsing does not happen at runtime: structures of `std::fmt::rt` are
1515
//! generated instead.
1616
17-
use prelude::*;
17+
#![crate_id = "fmt_macros#0.11-pre"]
18+
#![license = "MIT/ASL2"]
19+
#![crate_type = "rlib"]
20+
#![crate_type = "dylib"]
21+
#![feature(macro_rules, globs)]
22+
#![experimental]
1823

19-
use char;
20-
use owned::Box;
21-
use str;
24+
use std::char;
25+
use std::str;
2226

2327
/// A piece is a portion of the format string which represents the next part
2428
/// to emit. These are emitted as a stream by the `Parser` class.
@@ -164,7 +168,7 @@ pub struct PluralArm<'a> {
164168
/// is specially placed in the `Plural` variant of `Method`.
165169
///
166170
/// http://www.icu-project.org/apiref/icu4c/classicu_1_1PluralRules.html
167-
#[deriving(Eq, TotalEq, Hash)]
171+
#[deriving(Eq, TotalEq, Hash, Show)]
168172
#[allow(missing_doc)]
169173
pub enum PluralKeyword {
170174
/// The plural form for zero objects.
@@ -683,7 +687,6 @@ impl<'a> Parser<'a> {
683687
#[cfg(test)]
684688
mod tests {
685689
use super::*;
686-
use prelude::*;
687690

688691
fn same(fmt: &'static str, p: &[Piece<'static>]) {
689692
let mut parser = Parser::new(fmt);

src/libstd/fmt/mod.rs

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -510,9 +510,34 @@ pub use self::num::Radix;
510510
pub use self::num::RadixFmt;
511511

512512
mod num;
513-
pub mod parse;
514513
pub mod rt;
515514

515+
#[cfg(stage0)]
516+
#[allow(missing_doc)]
517+
pub mod parse {
518+
#[deriving(Eq)]
519+
pub enum Alignment {
520+
AlignLeft,
521+
AlignRight,
522+
AlignUnknown,
523+
}
524+
525+
pub enum PluralKeyword {
526+
Zero,
527+
One,
528+
Two,
529+
Few,
530+
Many,
531+
}
532+
533+
pub enum Flag {
534+
FlagSignPlus,
535+
FlagSignMinus,
536+
FlagAlternate,
537+
FlagSignAwareZeroPad,
538+
}
539+
}
540+
516541
pub type Result = io::IoResult<()>;
517542

518543
/// A struct to represent both where to emit formatting strings to and how they
@@ -524,7 +549,7 @@ pub struct Formatter<'a> {
524549
/// Character used as 'fill' whenever there is alignment
525550
pub fill: char,
526551
/// Boolean indication of whether the output should be left-aligned
527-
pub align: parse::Alignment,
552+
pub align: rt::Alignment,
528553
/// Optionally specified integer width that the output should be
529554
pub width: Option<uint>,
530555
/// Optionally specified precision for numeric types
@@ -757,7 +782,7 @@ pub unsafe fn write_unsafe(output: &mut io::Writer,
757782
width: None,
758783
precision: None,
759784
buf: output,
760-
align: parse::AlignUnknown,
785+
align: rt::AlignUnknown,
761786
fill: ' ',
762787
args: args,
763788
curarg: args.iter(),
@@ -890,15 +915,15 @@ impl<'a> Formatter<'a> {
890915
let value = value - match offset { Some(i) => i, None => 0 };
891916
for s in selectors.iter() {
892917
let run = match s.selector {
893-
rt::Keyword(parse::Zero) => value == 0,
894-
rt::Keyword(parse::One) => value == 1,
895-
rt::Keyword(parse::Two) => value == 2,
918+
rt::Keyword(rt::Zero) => value == 0,
919+
rt::Keyword(rt::One) => value == 1,
920+
rt::Keyword(rt::Two) => value == 2,
896921

897922
// FIXME: Few/Many should have a user-specified boundary
898923
// One possible option would be in the function
899924
// pointer of the 'arg: Argument' struct.
900-
rt::Keyword(parse::Few) => value < 8,
901-
rt::Keyword(parse::Many) => value >= 8,
925+
rt::Keyword(rt::Few) => value < 8,
926+
rt::Keyword(rt::Many) => value >= 8,
902927

903928
rt::Literal(..) => false
904929
};
@@ -960,7 +985,7 @@ impl<'a> Formatter<'a> {
960985
/// This function will correctly account for the flags provided as well as
961986
/// the minimum width. It will not take precision into account.
962987
pub fn pad_integral(&mut self, is_positive: bool, prefix: &str, buf: &[u8]) -> Result {
963-
use fmt::parse::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
988+
use fmt::rt::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
964989

965990
let mut width = buf.len();
966991

@@ -1000,11 +1025,11 @@ impl<'a> Formatter<'a> {
10001025
Some(min) if self.flags & (1 << (FlagSignAwareZeroPad as uint)) != 0 => {
10011026
self.fill = '0';
10021027
try!(write_prefix(self));
1003-
self.with_padding(min - width, parse::AlignRight, |f| f.buf.write(buf))
1028+
self.with_padding(min - width, rt::AlignRight, |f| f.buf.write(buf))
10041029
}
10051030
// Otherwise, the sign and prefix goes after the padding
10061031
Some(min) => {
1007-
self.with_padding(min - width, parse::AlignRight, |f| {
1032+
self.with_padding(min - width, rt::AlignRight, |f| {
10081033
try!(write_prefix(f)); f.buf.write(buf)
10091034
})
10101035
}
@@ -1055,7 +1080,7 @@ impl<'a> Formatter<'a> {
10551080
// If we're under both the maximum and the minimum width, then fill
10561081
// up the minimum width with the specified string + some alignment.
10571082
Some(width) => {
1058-
self.with_padding(width - s.len(), parse::AlignLeft, |me| {
1083+
self.with_padding(width - s.len(), rt::AlignLeft, |me| {
10591084
me.buf.write(s.as_bytes())
10601085
})
10611086
}
@@ -1066,21 +1091,21 @@ impl<'a> Formatter<'a> {
10661091
/// afterwards depending on whether right or left alingment is requested.
10671092
fn with_padding(&mut self,
10681093
padding: uint,
1069-
default: parse::Alignment,
1094+
default: rt::Alignment,
10701095
f: |&mut Formatter| -> Result) -> Result {
10711096
let align = match self.align {
1072-
parse::AlignUnknown => default,
1073-
parse::AlignLeft | parse::AlignRight => self.align
1097+
rt::AlignUnknown => default,
1098+
rt::AlignLeft | rt::AlignRight => self.align
10741099
};
1075-
if align == parse::AlignLeft {
1100+
if align == rt::AlignLeft {
10761101
try!(f(self));
10771102
}
10781103
let mut fill = [0u8, ..4];
10791104
let len = self.fill.encode_utf8(fill);
10801105
for _ in range(0, padding) {
10811106
try!(self.buf.write(fill.slice_to(len)));
10821107
}
1083-
if align == parse::AlignRight {
1108+
if align == rt::AlignRight {
10841109
try!(f(self));
10851110
}
10861111
Ok(())
@@ -1203,7 +1228,7 @@ impl<T> Poly for T {
12031228

12041229
impl<T> Pointer for *T {
12051230
fn fmt(&self, f: &mut Formatter) -> Result {
1206-
f.flags |= 1 << (parse::FlagAlternate as uint);
1231+
f.flags |= 1 << (rt::FlagAlternate as uint);
12071232
secret_lower_hex::<uint>(&(*self as uint), f)
12081233
}
12091234
}
@@ -1304,7 +1329,7 @@ impl<T: Show, U: Show> Show for ::result::Result<T, U> {
13041329

13051330
impl<'a, T: Show> Show for &'a [T] {
13061331
fn fmt(&self, f: &mut Formatter) -> Result {
1307-
if f.flags & (1 << (parse::FlagAlternate as uint)) == 0 {
1332+
if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
13081333
try!(write!(f.buf, "["));
13091334
}
13101335
let mut is_first = true;
@@ -1316,7 +1341,7 @@ impl<'a, T: Show> Show for &'a [T] {
13161341
}
13171342
try!(write!(f.buf, "{}", *x))
13181343
}
1319-
if f.flags & (1 << (parse::FlagAlternate as uint)) == 0 {
1344+
if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
13201345
try!(write!(f.buf, "]"));
13211346
}
13221347
Ok(())

src/libstd/fmt/rt.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,17 @@
1717
#![allow(missing_doc)]
1818
#![doc(hidden)]
1919

20-
use fmt::parse;
2120
use option::Option;
2221

22+
#[cfg(stage0)]
23+
pub use fmt::parse::{Alignment, AlignLeft, AlignRight, AlignUnknown};
24+
#[cfg(stage0)]
25+
pub use fmt::parse::{PluralKeyword, Zero, One, Two, Few, Many};
26+
#[cfg(stage0)]
27+
pub use fmt::parse::{Flag, FlagSignPlus, FlagSignMinus, FlagSignAwareZeroPad};
28+
#[cfg(stage0)]
29+
pub use fmt::parse::{FlagAlternate};
30+
2331
pub enum Piece<'a> {
2432
String(&'a str),
2533
// FIXME(#8259): this shouldn't require the unit-value here
@@ -35,12 +43,20 @@ pub struct Argument<'a> {
3543

3644
pub struct FormatSpec {
3745
pub fill: char,
38-
pub align: parse::Alignment,
46+
pub align: Alignment,
3947
pub flags: uint,
4048
pub precision: Count,
4149
pub width: Count,
4250
}
4351

52+
#[cfg(not(stage0))]
53+
#[deriving(Eq)]
54+
pub enum Alignment {
55+
AlignLeft,
56+
AlignRight,
57+
AlignUnknown,
58+
}
59+
4460
pub enum Count {
4561
CountIs(uint), CountIsParam(uint), CountIsNextParam, CountImplied,
4662
}
@@ -49,16 +65,32 @@ pub enum Position {
4965
ArgumentNext, ArgumentIs(uint)
5066
}
5167

68+
#[cfg(not(stage0))]
69+
pub enum Flag {
70+
FlagSignPlus,
71+
FlagSignMinus,
72+
FlagAlternate,
73+
FlagSignAwareZeroPad,
74+
}
75+
5276
pub enum Method<'a> {
5377
Plural(Option<uint>, &'a [PluralArm<'a>], &'a [Piece<'a>]),
5478
Select(&'a [SelectArm<'a>], &'a [Piece<'a>]),
5579
}
5680

5781
pub enum PluralSelector {
58-
Keyword(parse::PluralKeyword),
82+
Keyword(PluralKeyword),
5983
Literal(uint),
6084
}
6185

86+
pub enum PluralKeyword {
87+
Zero,
88+
One,
89+
Two,
90+
Few,
91+
Many,
92+
}
93+
6294
pub struct PluralArm<'a> {
6395
pub selector: PluralSelector,
6496
pub result: &'a [Piece<'a>],

src/libsyntax/ext/format.rs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use parse::token::InternedString;
1818
use parse::token;
1919
use rsparse = parse;
2020

21-
use std::fmt::parse;
21+
use parse = fmt_macros;
2222
use collections::{HashMap, HashSet};
2323

2424
#[deriving(Eq)]
@@ -232,7 +232,7 @@ impl<'a, 'b> Context<'a, 'b> {
232232
parse::Keyword(name) => {
233233
self.ecx.span_err(self.fmtsp,
234234
format!("duplicate selector \
235-
`{:?}`", name));
235+
`{}`", name));
236236
}
237237
parse::Literal(idx) => {
238238
self.ecx.span_err(self.fmtsp,
@@ -375,21 +375,11 @@ impl<'a, 'b> Context<'a, 'b> {
375375
return vec!(unnamed, allow_dead_code);
376376
}
377377

378-
fn parsepath(&self, s: &str) -> Vec<ast::Ident> {
379-
vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
380-
self.ecx.ident_of("parse"), self.ecx.ident_of(s))
381-
}
382-
383378
fn rtpath(&self, s: &str) -> Vec<ast::Ident> {
384379
vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
385380
self.ecx.ident_of("rt"), self.ecx.ident_of(s))
386381
}
387382

388-
fn ctpath(&self, s: &str) -> Vec<ast::Ident> {
389-
vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
390-
self.ecx.ident_of("parse"), self.ecx.ident_of(s))
391-
}
392-
393383
fn none(&self) -> @ast::Expr {
394384
let none = self.ecx.path_global(self.fmtsp, vec!(
395385
self.ecx.ident_of("std"),
@@ -475,7 +465,7 @@ impl<'a, 'b> Context<'a, 'b> {
475465
}).collect();
476466
let (lr, selarg) = match arm.selector {
477467
parse::Keyword(t) => {
478-
let p = self.ctpath(format!("{:?}", t));
468+
let p = self.rtpath(t.to_str());
479469
let p = self.ecx.path_global(sp, p);
480470
(self.rtpath("Keyword"), self.ecx.expr_path(p))
481471
}
@@ -564,13 +554,13 @@ impl<'a, 'b> Context<'a, 'b> {
564554
let fill = self.ecx.expr_lit(sp, ast::LitChar(fill));
565555
let align = match arg.format.align {
566556
parse::AlignLeft => {
567-
self.ecx.path_global(sp, self.parsepath("AlignLeft"))
557+
self.ecx.path_global(sp, self.rtpath("AlignLeft"))
568558
}
569559
parse::AlignRight => {
570-
self.ecx.path_global(sp, self.parsepath("AlignRight"))
560+
self.ecx.path_global(sp, self.rtpath("AlignRight"))
571561
}
572562
parse::AlignUnknown => {
573-
self.ecx.path_global(sp, self.parsepath("AlignUnknown"))
563+
self.ecx.path_global(sp, self.rtpath("AlignUnknown"))
574564
}
575565
};
576566
let align = self.ecx.expr_path(align);

src/libsyntax/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ extern crate term;
3535
extern crate collections;
3636
#[phase(syntax, link)]
3737
extern crate log;
38+
extern crate fmt_macros;
3839

3940
pub mod util {
4041
pub mod interner;

0 commit comments

Comments
 (0)