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]
This commit is contained in:
parent
87115fd001
commit
80487ddcad
@ -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
|
||||
|
@ -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);
|
@ -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(())
|
||||
|
@ -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>],
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user