about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2014-05-06 09:52:53 -0700
committerAlex Crichton <alex@alexcrichton.com>2014-05-08 09:35:59 -0700
commit80487ddcadda819e709beb9b996b12d322aa11a6 (patch)
tree6fa2208f015edd2e0007b5bba723405b2f5d7172
parent87115fd001440652291c509a77bda74fa511dab0 (diff)
downloadrust-80487ddcadda819e709beb9b996b12d322aa11a6.tar.gz
rust-80487ddcadda819e709beb9b996b12d322aa11a6.zip
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]
-rw-r--r--mk/crates.mk5
-rw-r--r--src/libfmt_macros/lib.rs (renamed from src/libstd/fmt/parse.rs)17
-rw-r--r--src/libstd/fmt/mod.rs65
-rw-r--r--src/libstd/fmt/rt.rs38
-rw-r--r--src/libsyntax/ext/format.rs22
-rw-r--r--src/libsyntax/lib.rs1
6 files changed, 100 insertions, 48 deletions
diff --git a/mk/crates.mk b/mk/crates.mk
index 9da80c2bc11..b75b5ba81e2 100644
--- a/mk/crates.mk
+++ b/mk/crates.mk
@@ -52,7 +52,7 @@
 TARGET_CRATES := libc std green rustuv native flate arena glob term semver \
                  uuid serialize sync getopts collections num test time rand \
 		 workcache url log regex graphviz core
-HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros
+HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros fmt_macros
 CRATES := $(TARGET_CRATES) $(HOST_CRATES)
 TOOLS := compiletest rustdoc rustc
 
@@ -61,7 +61,7 @@ DEPS_std := core libc native:rustrt native:compiler-rt native:backtrace
 DEPS_green := std rand native:context_switch
 DEPS_rustuv := std native:uv native:uv_support
 DEPS_native := std
-DEPS_syntax := std term serialize collections log
+DEPS_syntax := std term serialize collections log fmt_macros
 DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \
               collections time log
 DEPS_rustdoc := rustc native:hoedown serialize sync getopts collections \
@@ -88,6 +88,7 @@ DEPS_workcache := std serialize collections log
 DEPS_log := std sync
 DEPS_regex := std collections
 DEPS_regex_macros = syntax std regex
+DEPS_fmt_macros = std
 
 TOOL_DEPS_compiletest := test green rustuv getopts
 TOOL_DEPS_rustdoc := rustdoc native
diff --git a/src/libstd/fmt/parse.rs b/src/libfmt_macros/lib.rs
index ba126e00153..91b3fefdd02 100644
--- a/src/libstd/fmt/parse.rs
+++ b/src/libfmt_macros/lib.rs
@@ -8,17 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! Parsing of format strings
+//! Macro support for format strings
 //!
 //! These structures are used when parsing format strings for the compiler.
 //! Parsing does not happen at runtime: structures of `std::fmt::rt` are
 //! generated instead.
 
-use prelude::*;
+#![crate_id = "fmt_macros#0.11-pre"]
+#![license = "MIT/ASL2"]
+#![crate_type = "rlib"]
+#![crate_type = "dylib"]
+#![feature(macro_rules, globs)]
+#![experimental]
 
-use char;
-use owned::Box;
-use str;
+use std::char;
+use std::str;
 
 /// A piece is a portion of the format string which represents the next part
 /// to emit. These are emitted as a stream by the `Parser` class.
@@ -164,7 +168,7 @@ pub struct PluralArm<'a> {
 /// is specially placed in the `Plural` variant of `Method`.
 ///
 /// http://www.icu-project.org/apiref/icu4c/classicu_1_1PluralRules.html
-#[deriving(Eq, TotalEq, Hash)]
+#[deriving(Eq, TotalEq, Hash, Show)]
 #[allow(missing_doc)]
 pub enum PluralKeyword {
     /// The plural form for zero objects.
@@ -683,7 +687,6 @@ impl<'a> Parser<'a> {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use prelude::*;
 
     fn same(fmt: &'static str, p: &[Piece<'static>]) {
         let mut parser = Parser::new(fmt);
diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs
index 74ab874d319..8846fa3f6f3 100644
--- a/src/libstd/fmt/mod.rs
+++ b/src/libstd/fmt/mod.rs
@@ -510,9 +510,34 @@ pub use self::num::Radix;
 pub use self::num::RadixFmt;
 
 mod num;
-pub mod parse;
 pub mod rt;
 
+#[cfg(stage0)]
+#[allow(missing_doc)]
+pub mod parse {
+    #[deriving(Eq)]
+    pub enum Alignment {
+        AlignLeft,
+        AlignRight,
+        AlignUnknown,
+    }
+
+    pub enum PluralKeyword {
+        Zero,
+        One,
+        Two,
+        Few,
+        Many,
+    }
+
+    pub enum Flag {
+        FlagSignPlus,
+        FlagSignMinus,
+        FlagAlternate,
+        FlagSignAwareZeroPad,
+    }
+}
+
 pub type Result = io::IoResult<()>;
 
 /// A struct to represent both where to emit formatting strings to and how they
@@ -524,7 +549,7 @@ pub struct Formatter<'a> {
     /// Character used as 'fill' whenever there is alignment
     pub fill: char,
     /// Boolean indication of whether the output should be left-aligned
-    pub align: parse::Alignment,
+    pub align: rt::Alignment,
     /// Optionally specified integer width that the output should be
     pub width: Option<uint>,
     /// Optionally specified precision for numeric types
@@ -757,7 +782,7 @@ pub unsafe fn write_unsafe(output: &mut io::Writer,
         width: None,
         precision: None,
         buf: output,
-        align: parse::AlignUnknown,
+        align: rt::AlignUnknown,
         fill: ' ',
         args: args,
         curarg: args.iter(),
@@ -890,15 +915,15 @@ impl<'a> Formatter<'a> {
                 let value = value - match offset { Some(i) => i, None => 0 };
                 for s in selectors.iter() {
                     let run = match s.selector {
-                        rt::Keyword(parse::Zero) => value == 0,
-                        rt::Keyword(parse::One) => value == 1,
-                        rt::Keyword(parse::Two) => value == 2,
+                        rt::Keyword(rt::Zero) => value == 0,
+                        rt::Keyword(rt::One) => value == 1,
+                        rt::Keyword(rt::Two) => value == 2,
 
                         // FIXME: Few/Many should have a user-specified boundary
                         //      One possible option would be in the function
                         //      pointer of the 'arg: Argument' struct.
-                        rt::Keyword(parse::Few) => value < 8,
-                        rt::Keyword(parse::Many) => value >= 8,
+                        rt::Keyword(rt::Few) => value < 8,
+                        rt::Keyword(rt::Many) => value >= 8,
 
                         rt::Literal(..) => false
                     };
@@ -960,7 +985,7 @@ impl<'a> Formatter<'a> {
     /// This function will correctly account for the flags provided as well as
     /// the minimum width. It will not take precision into account.
     pub fn pad_integral(&mut self, is_positive: bool, prefix: &str, buf: &[u8]) -> Result {
-        use fmt::parse::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
+        use fmt::rt::{FlagAlternate, FlagSignPlus, FlagSignAwareZeroPad};
 
         let mut width = buf.len();
 
@@ -1000,11 +1025,11 @@ impl<'a> Formatter<'a> {
             Some(min) if self.flags & (1 << (FlagSignAwareZeroPad as uint)) != 0 => {
                 self.fill = '0';
                 try!(write_prefix(self));
-                self.with_padding(min - width, parse::AlignRight, |f| f.buf.write(buf))
+                self.with_padding(min - width, rt::AlignRight, |f| f.buf.write(buf))
             }
             // Otherwise, the sign and prefix goes after the padding
             Some(min) => {
-                self.with_padding(min - width, parse::AlignRight, |f| {
+                self.with_padding(min - width, rt::AlignRight, |f| {
                     try!(write_prefix(f)); f.buf.write(buf)
                 })
             }
@@ -1055,7 +1080,7 @@ impl<'a> Formatter<'a> {
             // If we're under both the maximum and the minimum width, then fill
             // up the minimum width with the specified string + some alignment.
             Some(width) => {
-                self.with_padding(width - s.len(), parse::AlignLeft, |me| {
+                self.with_padding(width - s.len(), rt::AlignLeft, |me| {
                     me.buf.write(s.as_bytes())
                 })
             }
@@ -1066,13 +1091,13 @@ impl<'a> Formatter<'a> {
     /// afterwards depending on whether right or left alingment is requested.
     fn with_padding(&mut self,
                     padding: uint,
-                    default: parse::Alignment,
+                    default: rt::Alignment,
                     f: |&mut Formatter| -> Result) -> Result {
         let align = match self.align {
-            parse::AlignUnknown => default,
-            parse::AlignLeft | parse::AlignRight => self.align
+            rt::AlignUnknown => default,
+            rt::AlignLeft | rt::AlignRight => self.align
         };
-        if align == parse::AlignLeft {
+        if align == rt::AlignLeft {
             try!(f(self));
         }
         let mut fill = [0u8, ..4];
@@ -1080,7 +1105,7 @@ impl<'a> Formatter<'a> {
         for _ in range(0, padding) {
             try!(self.buf.write(fill.slice_to(len)));
         }
-        if align == parse::AlignRight {
+        if align == rt::AlignRight {
             try!(f(self));
         }
         Ok(())
@@ -1203,7 +1228,7 @@ impl<T> Poly for T {
 
 impl<T> Pointer for *T {
     fn fmt(&self, f: &mut Formatter) -> Result {
-        f.flags |= 1 << (parse::FlagAlternate as uint);
+        f.flags |= 1 << (rt::FlagAlternate as uint);
         secret_lower_hex::<uint>(&(*self as uint), f)
     }
 }
@@ -1304,7 +1329,7 @@ impl<T: Show, U: Show> Show for ::result::Result<T, U> {
 
 impl<'a, T: Show> Show for &'a [T] {
     fn fmt(&self, f: &mut Formatter) -> Result {
-        if f.flags & (1 << (parse::FlagAlternate as uint)) == 0 {
+        if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
             try!(write!(f.buf, "["));
         }
         let mut is_first = true;
@@ -1316,7 +1341,7 @@ impl<'a, T: Show> Show for &'a [T] {
             }
             try!(write!(f.buf, "{}", *x))
         }
-        if f.flags & (1 << (parse::FlagAlternate as uint)) == 0 {
+        if f.flags & (1 << (rt::FlagAlternate as uint)) == 0 {
             try!(write!(f.buf, "]"));
         }
         Ok(())
diff --git a/src/libstd/fmt/rt.rs b/src/libstd/fmt/rt.rs
index 01c2c06c3fb..33e86a4485b 100644
--- a/src/libstd/fmt/rt.rs
+++ b/src/libstd/fmt/rt.rs
@@ -17,9 +17,17 @@
 #![allow(missing_doc)]
 #![doc(hidden)]
 
-use fmt::parse;
 use option::Option;
 
+#[cfg(stage0)]
+pub use fmt::parse::{Alignment, AlignLeft, AlignRight, AlignUnknown};
+#[cfg(stage0)]
+pub use fmt::parse::{PluralKeyword, Zero, One, Two, Few, Many};
+#[cfg(stage0)]
+pub use fmt::parse::{Flag, FlagSignPlus, FlagSignMinus, FlagSignAwareZeroPad};
+#[cfg(stage0)]
+pub use fmt::parse::{FlagAlternate};
+
 pub enum Piece<'a> {
     String(&'a str),
     // FIXME(#8259): this shouldn't require the unit-value here
@@ -35,12 +43,20 @@ pub struct Argument<'a> {
 
 pub struct FormatSpec {
     pub fill: char,
-    pub align: parse::Alignment,
+    pub align: Alignment,
     pub flags: uint,
     pub precision: Count,
     pub width: Count,
 }
 
+#[cfg(not(stage0))]
+#[deriving(Eq)]
+pub enum Alignment {
+    AlignLeft,
+    AlignRight,
+    AlignUnknown,
+}
+
 pub enum Count {
     CountIs(uint), CountIsParam(uint), CountIsNextParam, CountImplied,
 }
@@ -49,16 +65,32 @@ pub enum Position {
     ArgumentNext, ArgumentIs(uint)
 }
 
+#[cfg(not(stage0))]
+pub enum Flag {
+    FlagSignPlus,
+    FlagSignMinus,
+    FlagAlternate,
+    FlagSignAwareZeroPad,
+}
+
 pub enum Method<'a> {
     Plural(Option<uint>, &'a [PluralArm<'a>], &'a [Piece<'a>]),
     Select(&'a [SelectArm<'a>], &'a [Piece<'a>]),
 }
 
 pub enum PluralSelector {
-    Keyword(parse::PluralKeyword),
+    Keyword(PluralKeyword),
     Literal(uint),
 }
 
+pub enum PluralKeyword {
+    Zero,
+    One,
+    Two,
+    Few,
+    Many,
+}
+
 pub struct PluralArm<'a> {
     pub selector: PluralSelector,
     pub result: &'a [Piece<'a>],
diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs
index fc3136996ae..7b465a2dc35 100644
--- a/src/libsyntax/ext/format.rs
+++ b/src/libsyntax/ext/format.rs
@@ -18,7 +18,7 @@ use parse::token::InternedString;
 use parse::token;
 use rsparse = parse;
 
-use std::fmt::parse;
+use parse = fmt_macros;
 use collections::{HashMap, HashSet};
 
 #[deriving(Eq)]
@@ -232,7 +232,7 @@ impl<'a, 'b> Context<'a, 'b> {
                             parse::Keyword(name) => {
                                 self.ecx.span_err(self.fmtsp,
                                                   format!("duplicate selector \
-                                                           `{:?}`", name));
+                                                           `{}`", name));
                             }
                             parse::Literal(idx) => {
                                 self.ecx.span_err(self.fmtsp,
@@ -375,21 +375,11 @@ impl<'a, 'b> Context<'a, 'b> {
         return vec!(unnamed, allow_dead_code);
     }
 
-    fn parsepath(&self, s: &str) -> Vec<ast::Ident> {
-        vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
-          self.ecx.ident_of("parse"), self.ecx.ident_of(s))
-    }
-
     fn rtpath(&self, s: &str) -> Vec<ast::Ident> {
         vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
           self.ecx.ident_of("rt"), self.ecx.ident_of(s))
     }
 
-    fn ctpath(&self, s: &str) -> Vec<ast::Ident> {
-        vec!(self.ecx.ident_of("std"), self.ecx.ident_of("fmt"),
-          self.ecx.ident_of("parse"), self.ecx.ident_of(s))
-    }
-
     fn none(&self) -> @ast::Expr {
         let none = self.ecx.path_global(self.fmtsp, vec!(
                 self.ecx.ident_of("std"),
@@ -475,7 +465,7 @@ impl<'a, 'b> Context<'a, 'b> {
                             }).collect();
                         let (lr, selarg) = match arm.selector {
                             parse::Keyword(t) => {
-                                let p = self.ctpath(format!("{:?}", t));
+                                let p = self.rtpath(t.to_str());
                                 let p = self.ecx.path_global(sp, p);
                                 (self.rtpath("Keyword"), self.ecx.expr_path(p))
                             }
@@ -564,13 +554,13 @@ impl<'a, 'b> Context<'a, 'b> {
                 let fill = self.ecx.expr_lit(sp, ast::LitChar(fill));
                 let align = match arg.format.align {
                     parse::AlignLeft => {
-                        self.ecx.path_global(sp, self.parsepath("AlignLeft"))
+                        self.ecx.path_global(sp, self.rtpath("AlignLeft"))
                     }
                     parse::AlignRight => {
-                        self.ecx.path_global(sp, self.parsepath("AlignRight"))
+                        self.ecx.path_global(sp, self.rtpath("AlignRight"))
                     }
                     parse::AlignUnknown => {
-                        self.ecx.path_global(sp, self.parsepath("AlignUnknown"))
+                        self.ecx.path_global(sp, self.rtpath("AlignUnknown"))
                     }
                 };
                 let align = self.ecx.expr_path(align);
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 012bc50ecab..5e1d988df5c 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -35,6 +35,7 @@ extern crate term;
 extern crate collections;
 #[phase(syntax, link)]
 extern crate log;
+extern crate fmt_macros;
 
 pub mod util {
     pub mod interner;