@@ -470,6 +470,9 @@ pub mod ct {
470
470
// decisions made a runtime. If it proves worthwhile then some of these
471
471
// conditions can be evaluated at compile-time. For now though it's cleaner to
472
472
// implement it this way, I think.
473
+ #[cfg(stage1)]
474
+ #[cfg(stage2)]
475
+ #[cfg(stage3)]
473
476
#[doc(hidden)]
474
477
pub mod rt {
475
478
use float;
@@ -673,6 +676,192 @@ pub mod rt {
673
676
}
674
677
}
675
678
679
+ // XXX: remove after a snapshot of the above changes have gone in
680
+ #[cfg(stage0)]
681
+ #[doc(hidden)]
682
+ pub mod rt {
683
+ use float;
684
+ use str;
685
+ use sys;
686
+ use uint;
687
+ use vec;
688
+
689
+ pub static flag_none : u32 = 0u32;
690
+ pub static flag_left_justify : u32 = 0b00000000000001u32;
691
+ pub static flag_left_zero_pad : u32 = 0b00000000000010u32;
692
+ pub static flag_space_for_sign : u32 = 0b00000000000100u32;
693
+ pub static flag_sign_always : u32 = 0b00000000001000u32;
694
+ pub static flag_alternate : u32 = 0b00000000010000u32;
695
+
696
+ pub enum Count { CountIs(uint), CountImplied, }
697
+
698
+ pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, }
699
+
700
+ pub struct Conv {
701
+ flags: u32,
702
+ width: Count,
703
+ precision: Count,
704
+ ty: Ty,
705
+ }
706
+
707
+ pub fn conv_int(cv: Conv, i: int) -> ~str {
708
+ let radix = 10;
709
+ let prec = get_int_precision(cv);
710
+ let mut s : ~str = int_to_str_prec(i, radix, prec);
711
+ if 0 <= i {
712
+ if have_flag(cv.flags, flag_sign_always) {
713
+ unsafe { str::unshift_char(&mut s, '+') };
714
+ } else if have_flag(cv.flags, flag_space_for_sign) {
715
+ unsafe { str::unshift_char(&mut s, ' ') };
716
+ }
717
+ }
718
+ return unsafe { pad(cv, s, PadSigned) };
719
+ }
720
+ pub fn conv_uint(cv: Conv, u: uint) -> ~str {
721
+ let prec = get_int_precision(cv);
722
+ let mut rs =
723
+ match cv.ty {
724
+ TyDefault => uint_to_str_prec(u, 10, prec),
725
+ TyHexLower => uint_to_str_prec(u, 16, prec),
726
+ TyHexUpper => str::to_upper(uint_to_str_prec(u, 16, prec)),
727
+ TyBits => uint_to_str_prec(u, 2, prec),
728
+ TyOctal => uint_to_str_prec(u, 8, prec)
729
+ };
730
+ return unsafe { pad(cv, rs, PadUnsigned) };
731
+ }
732
+ pub fn conv_bool(cv: Conv, b: bool) -> ~str {
733
+ let s = if b { ~" true " } else { ~" false " };
734
+ // run the boolean conversion through the string conversion logic,
735
+ // giving it the same rules for precision, etc.
736
+ return conv_str(cv, s);
737
+ }
738
+ pub fn conv_char(cv: Conv, c: char) -> ~str {
739
+ let mut s = str::from_char(c);
740
+ return unsafe { pad(cv, s, PadNozero) };
741
+ }
742
+ pub fn conv_str(cv: Conv, s: &str) -> ~str {
743
+ // For strings, precision is the maximum characters
744
+ // displayed
745
+ let mut unpadded = match cv.precision {
746
+ CountImplied => s.to_owned(),
747
+ CountIs(max) => if (max as uint) < str::char_len(s) {
748
+ str::substr(s, 0, max as uint).to_owned()
749
+ } else {
750
+ s.to_owned()
751
+ }
752
+ };
753
+ return unsafe { pad(cv, unpadded, PadNozero) };
754
+ }
755
+ pub fn conv_float(cv: Conv, f: float) -> ~str {
756
+ let (to_str, digits) = match cv.precision {
757
+ CountIs(c) => (float::to_str_exact, c as uint),
758
+ CountImplied => (float::to_str_digits, 6u)
759
+ };
760
+ let mut s = unsafe { to_str(f, digits) };
761
+ if 0.0 <= f {
762
+ if have_flag(cv.flags, flag_sign_always) {
763
+ s = ~" +" + s;
764
+ } else if have_flag(cv.flags, flag_space_for_sign) {
765
+ s = ~" " + s;
766
+ }
767
+ }
768
+ return unsafe { pad(cv, s, PadFloat) };
769
+ }
770
+ pub fn conv_poly<T>(cv: Conv, v: &T) -> ~str {
771
+ let s = sys::log_str(v);
772
+ return conv_str(cv, s);
773
+ }
774
+
775
+ // Convert an int to string with minimum number of digits. If precision is
776
+ // 0 and num is 0 then the result is the empty string.
777
+ pub fn int_to_str_prec(num: int, radix: uint, prec: uint) -> ~str {
778
+ return if num < 0 {
779
+ ~" -" + uint_to_str_prec(-num as uint, radix, prec)
780
+ } else { uint_to_str_prec(num as uint, radix, prec) };
781
+ }
782
+
783
+ // Convert a uint to string with a minimum number of digits. If precision
784
+ // is 0 and num is 0 then the result is the empty string. Could move this
785
+ // to uint: but it doesn't seem all that useful.
786
+ pub fn uint_to_str_prec(num: uint, radix: uint,
787
+ prec: uint) -> ~str {
788
+ return if prec == 0u && num == 0u {
789
+ ~" "
790
+ } else {
791
+ let s = uint::to_str_radix(num, radix);
792
+ let len = str::char_len(s);
793
+ if len < prec {
794
+ let diff = prec - len;
795
+ let pad = str::from_chars(vec::from_elem(diff, '0'));
796
+ pad + s
797
+ } else { s }
798
+ };
799
+ }
800
+ pub fn get_int_precision(cv: Conv) -> uint {
801
+ return match cv.precision {
802
+ CountIs(c) => c as uint,
803
+ CountImplied => 1u
804
+ };
805
+ }
806
+
807
+ #[deriving(Eq)]
808
+ pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat }
809
+
810
+ pub fn pad(cv: Conv, s: ~str, mode: PadMode) -> ~str {
811
+ let mut s = s; // sadtimes
812
+ let uwidth : uint = match cv.width {
813
+ CountImplied => return (s),
814
+ CountIs(width) => { width as uint }
815
+ };
816
+ let strlen = str::char_len(s);
817
+ if uwidth <= strlen { return (s); }
818
+ let mut padchar = ' ';
819
+ let diff = uwidth - strlen;
820
+ if have_flag(cv.flags, flag_left_justify) {
821
+ let padstr = str::from_chars(vec::from_elem(diff, padchar));
822
+ return s + padstr;
823
+ }
824
+ let (might_zero_pad, signed) = match mode {
825
+ PadNozero => (false, true),
826
+ PadSigned => (true, true),
827
+ PadFloat => (true, true),
828
+ PadUnsigned => (true, false)
829
+ };
830
+ fn have_precision(cv: Conv) -> bool {
831
+ return match cv.precision { CountImplied => false, _ => true };
832
+ }
833
+ let zero_padding = {
834
+ if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) &&
835
+ (!have_precision(cv) || mode == PadFloat) {
836
+ padchar = '0';
837
+ true
838
+ } else {
839
+ false
840
+ }
841
+ };
842
+ let padstr = str::from_chars(vec::from_elem(diff, padchar));
843
+ // This is completely heinous. If we have a signed value then
844
+ // potentially rip apart the intermediate result and insert some
845
+ // zeros. It may make sense to convert zero padding to a precision
846
+ // instead.
847
+
848
+ if signed && zero_padding && s.len() > 0 {
849
+ let head = str::shift_char(&mut s);
850
+ if head == '+' || head == '-' || head == ' ' {
851
+ let headstr = str::from_chars(vec::from_elem(1u, head));
852
+ return headstr + padstr + s;
853
+ }
854
+ else {
855
+ str::unshift_char(&mut s, head);
856
+ }
857
+ }
858
+ return padstr + s;
859
+ }
860
+ pub fn have_flag(flags: u32, f: u32) -> bool {
861
+ flags & f != 0
862
+ }
863
+ }
864
+
676
865
// Bulk of the tests are in src/test/run-pass/syntax-extension-fmt.rs
677
866
#[cfg(test)]
678
867
mod test {
0 commit comments