@@ -470,6 +470,215 @@ 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)]
476
+ #[doc(hidden)]
477
+ pub mod rt {
478
+ use float;
479
+ use str;
480
+ use sys;
481
+ use int;
482
+ use uint;
483
+ use vec;
484
+ use option::{Some, None, Option};
485
+
486
+ pub const flag_none : u32 = 0u32;
487
+ pub const flag_left_justify : u32 = 0b00000000000001u32;
488
+ pub const flag_left_zero_pad : u32 = 0b00000000000010u32;
489
+ pub const flag_space_for_sign : u32 = 0b00000000000100u32;
490
+ pub const flag_sign_always : u32 = 0b00000000001000u32;
491
+ pub const flag_alternate : u32 = 0b00000000010000u32;
492
+
493
+ pub enum Count { CountIs(uint), CountImplied, }
494
+
495
+ pub enum Ty { TyDefault, TyBits, TyHexUpper, TyHexLower, TyOctal, }
496
+
497
+ pub struct Conv {
498
+ flags: u32,
499
+ width: Count,
500
+ precision: Count,
501
+ ty: Ty,
502
+ }
503
+
504
+ pub pure fn conv_int(cv: Conv, i: int, buf: &mut ~str) {
505
+ let radix = 10;
506
+ let prec = get_int_precision(cv);
507
+ let mut s : ~str = uint_to_str_prec(int::abs(i) as uint, radix, prec);
508
+
509
+ let head = if i >= 0 {
510
+ if have_flag(cv.flags, flag_sign_always) {
511
+ Some('+')
512
+ } else if have_flag(cv.flags, flag_space_for_sign) {
513
+ Some(' ')
514
+ } else {
515
+ None
516
+ }
517
+ } else { Some('-') };
518
+ unsafe { pad(cv, s, head, PadSigned, buf) };
519
+ }
520
+ pub pure fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) {
521
+ let prec = get_int_precision(cv);
522
+ let mut rs =
523
+ match cv.ty {
524
+ TyDefault => uint_to_str_prec(u, 10, prec),
525
+ TyHexLower => uint_to_str_prec(u, 16, prec),
526
+ TyHexUpper => str::to_upper(uint_to_str_prec(u, 16, prec)),
527
+ TyBits => uint_to_str_prec(u, 2, prec),
528
+ TyOctal => uint_to_str_prec(u, 8, prec)
529
+ };
530
+ unsafe { pad(cv, rs, None, PadUnsigned, buf) };
531
+ }
532
+ pub pure fn conv_bool(cv: Conv, b: bool, buf: &mut ~str) {
533
+ let s = if b { " true " } else { " false " };
534
+ // run the boolean conversion through the string conversion logic,
535
+ // giving it the same rules for precision, etc.
536
+ conv_str(cv, s, buf);
537
+ }
538
+ pub pure fn conv_char(cv: Conv, c: char, buf: &mut ~str) {
539
+ unsafe { pad(cv, " ", Some(c), PadNozero, buf) };
540
+ }
541
+ pub pure fn conv_str(cv: Conv, s: &str, buf: &mut ~str) {
542
+ // For strings, precision is the maximum characters
543
+ // displayed
544
+ let mut unpadded = match cv.precision {
545
+ CountImplied => s,
546
+ CountIs(max) => if (max as uint) < str::char_len(s) {
547
+ str::slice(s, 0, max as uint)
548
+ } else {
549
+ s
550
+ }
551
+ };
552
+ unsafe { pad(cv, unpadded, None, PadNozero, buf) };
553
+ }
554
+ pub pure fn conv_float(cv: Conv, f: float, buf: &mut ~str) {
555
+ let (to_str, digits) = match cv.precision {
556
+ CountIs(c) => (float::to_str_exact, c as uint),
557
+ CountImplied => (float::to_str_digits, 6u)
558
+ };
559
+ let mut s = unsafe { to_str(f, digits) };
560
+ let head = if 0.0 <= f {
561
+ if have_flag(cv.flags, flag_sign_always) {
562
+ Some('+')
563
+ } else if have_flag(cv.flags, flag_space_for_sign) {
564
+ Some(' ')
565
+ } else {
566
+ None
567
+ }
568
+ } else { None };
569
+ unsafe { pad(cv, s, head, PadFloat, buf) };
570
+ }
571
+ pub pure fn conv_poly<T>(cv: Conv, v: &T, buf: &mut ~str) {
572
+ let s = sys::log_str(v);
573
+ conv_str(cv, s, buf);
574
+ }
575
+
576
+ // Convert a uint to string with a minimum number of digits. If precision
577
+ // is 0 and num is 0 then the result is the empty string. Could move this
578
+ // to uint: but it doesn't seem all that useful.
579
+ pub pure fn uint_to_str_prec(num: uint, radix: uint,
580
+ prec: uint) -> ~str {
581
+ return if prec == 0u && num == 0u {
582
+ ~" "
583
+ } else {
584
+ let s = uint::to_str_radix(num, radix);
585
+ let len = str::char_len(s);
586
+ if len < prec {
587
+ let diff = prec - len;
588
+ let pad = str::from_chars(vec::from_elem(diff, '0'));
589
+ pad + s
590
+ } else { s }
591
+ };
592
+ }
593
+ pub pure fn get_int_precision(cv: Conv) -> uint {
594
+ return match cv.precision {
595
+ CountIs(c) => c as uint,
596
+ CountImplied => 1u
597
+ };
598
+ }
599
+
600
+ #[deriving(Eq)]
601
+ pub enum PadMode { PadSigned, PadUnsigned, PadNozero, PadFloat }
602
+
603
+ pub fn pad(cv: Conv, mut s: &str, head: Option<char>, mode: PadMode,
604
+ buf: &mut ~str) {
605
+ let headsize = match head { Some(_) => 1, _ => 0 };
606
+ let uwidth : uint = match cv.width {
607
+ CountImplied => {
608
+ for head.each |&c| {
609
+ buf.push_char(c);
610
+ }
611
+ return buf.push_str(s);
612
+ }
613
+ CountIs(width) => { width as uint }
614
+ };
615
+ let strlen = str::char_len(s) + headsize;
616
+ if uwidth <= strlen {
617
+ for head.each |&c| {
618
+ buf.push_char(c);
619
+ }
620
+ return buf.push_str(s);
621
+ }
622
+ let mut padchar = ' ';
623
+ let diff = uwidth - strlen;
624
+ if have_flag(cv.flags, flag_left_justify) {
625
+ for head.each |&c| {
626
+ buf.push_char(c);
627
+ }
628
+ buf.push_str(s);
629
+ for diff.times {
630
+ buf.push_char(padchar);
631
+ }
632
+ return;
633
+ }
634
+ let (might_zero_pad, signed) = match mode {
635
+ PadNozero => (false, true),
636
+ PadSigned => (true, true),
637
+ PadFloat => (true, true),
638
+ PadUnsigned => (true, false)
639
+ };
640
+ pure fn have_precision(cv: Conv) -> bool {
641
+ return match cv.precision { CountImplied => false, _ => true };
642
+ }
643
+ let zero_padding = {
644
+ if might_zero_pad && have_flag(cv.flags, flag_left_zero_pad) &&
645
+ (!have_precision(cv) || mode == PadFloat) {
646
+ padchar = '0';
647
+ true
648
+ } else {
649
+ false
650
+ }
651
+ };
652
+ let padstr = str::from_chars(vec::from_elem(diff, padchar));
653
+ // This is completely heinous. If we have a signed value then
654
+ // potentially rip apart the intermediate result and insert some
655
+ // zeros. It may make sense to convert zero padding to a precision
656
+ // instead.
657
+
658
+ if signed && zero_padding {
659
+ for head.each |&head| {
660
+ if head == '+' || head == '-' || head == ' ' {
661
+ buf.push_char(head);
662
+ buf.push_str(padstr);
663
+ buf.push_str(s);
664
+ return;
665
+ }
666
+ }
667
+ }
668
+ buf.push_str(padstr);
669
+ for head.each |&c| {
670
+ buf.push_char(c);
671
+ }
672
+ buf.push_str(s);
673
+ }
674
+ #[inline(always)]
675
+ pub pure fn have_flag(flags: u32, f: u32) -> bool {
676
+ flags & f != 0
677
+ }
678
+ }
679
+
680
+ // XXX: remove after a snapshot of the above changes have gone in
681
+ #[cfg(stage0)]
473
682
#[doc(hidden)]
474
683
pub mod rt {
475
684
use float;
0 commit comments