diff --git a/basis/calendar/format/format.factor b/basis/calendar/format/format.factor index 35c7f032ce..96d4afcfae 100644 --- a/basis/calendar/format/format.factor +++ b/basis/calendar/format/format.factor @@ -150,7 +150,7 @@ M: timestamp year. ( timestamp -- ) ! Should be enough for anyone, allows to not do a fancy ! algorithm to detect infinite decimals (e.g 1/3) : ss.SSSSSS ( timestamp -- ) - second>> >float "%09.6f" format-float write ; + second>> >float "0" 9 6 "f" "C" format-float write ; : (timestamp>rfc3339) ( timestamp -- ) { diff --git a/basis/formatting/formatting.factor b/basis/formatting/formatting.factor index f36b042622..697dc693cc 100644 --- a/basis/formatting/formatting.factor +++ b/basis/formatting/formatting.factor @@ -30,8 +30,7 @@ IN: formatting [ 0 ] [ string>number ] if-empty ; : format-simple ( x digits string -- string ) - [ [ >float ] [ number>string ] bi* "%." ] dip - surround format-float ; + [ >float "" -1 ] 2dip "" format-float ; : format-scientific ( x digits -- string ) "e" format-simple ; diff --git a/basis/stack-checker/known-words/known-words.factor b/basis/stack-checker/known-words/known-words.factor index 02b4f29562..5ad4733548 100644 --- a/basis/stack-checker/known-words/known-words.factor +++ b/basis/stack-checker/known-words/known-words.factor @@ -420,7 +420,7 @@ M: object infer-call* \ call bad-macro-input ; { fixnum>float { fixnum } { float } } ! float - { (format-float) { float byte-array } { byte-array } } + { (format-float) { float byte-array fixnum fixnum byte-array byte-array } { byte-array } } { bits>float { integer } { float } } { float* { float float } { float } } { float+ { float float } { float } } diff --git a/core/bootstrap/primitives.factor b/core/bootstrap/primitives.factor index ca5bb6f95d..5079cf6acf 100755 --- a/core/bootstrap/primitives.factor +++ b/core/bootstrap/primitives.factor @@ -476,7 +476,7 @@ tuple { "bits>float" "math" "primitive_bits_float" ( n -- x ) } { "double>bits" "math" "primitive_double_bits" ( x -- n ) } { "float>bits" "math" "primitive_float_bits" ( x -- n ) } - { "(format-float)" "math.parser.private" "primitive_format_float" ( n format -- byte-array ) } + { "(format-float)" "math.parser.private" "primitive_format_float" ( n fill width precision format locale -- byte-array ) } { "bignum*" "math.private" "primitive_bignum_multiply" ( x y -- z ) } { "bignum+" "math.private" "primitive_bignum_add" ( x y -- z ) } { "bignum-" "math.private" "primitive_bignum_subtract" ( x y -- z ) } diff --git a/core/math/parser/parser.factor b/core/math/parser/parser.factor index de8f60ce1d..0c4ecd8934 100644 --- a/core/math/parser/parser.factor +++ b/core/math/parser/parser.factor @@ -6,7 +6,7 @@ sequences.private splitting strings strings.private ; IN: math.parser : digit> ( ch -- n ) @@ -488,12 +488,12 @@ M: ratio >base base ] 2curry each-integer ] keep ; inline -: format-float ( n format -- string ) - format-string (format-float) - dup [ 0 = ] find drop - format-head fix-float ; inline +: format-float ( n fill width precision format locale -- string ) + [ + [ format-string ] 4dip [ format-string ] bi@ (format-float) + dup [ 0 = ] find drop format-head + ] [ + "C" = [ [ "G" = ] [ "E" = ] bi or "E" "e" ? fix-float ] [ drop ] if + ] 2bi ; inline : float>base ( n radix -- str ) { - { 10 [ "%.16g" format-float ] } + { 10 [ "" -1 16 "" "C" format-float ] } [ bin-float>base ] } case ; inline diff --git a/vm/math.cpp b/vm/math.cpp index e46dc80b62..c2b5714013 100644 --- a/vm/math.cpp +++ b/vm/math.cpp @@ -1,4 +1,6 @@ #include "master.hpp" +#include +#include namespace factor { @@ -211,10 +213,36 @@ void factor_vm::primitive_fixnum_to_float() { /* Allocates memory */ void factor_vm::primitive_format_float() { - byte_array* array = allot_byte_array(100); + char* locale = alien_offset(ctx->pop()); char* format = alien_offset(ctx->pop()); + fixnum precision = untag_fixnum(ctx->pop()); + fixnum width = untag_fixnum(ctx->pop()); + char* fill = alien_offset(ctx->pop()); double value = untag_float_check(ctx->peek()); - SNPRINTF(array->data(), 99, format, value); + std::ostringstream localized_stream; + localized_stream.imbue(std::locale(locale)); + switch (format[0]) { + case 'f': localized_stream << std::fixed; break; + case 'e': localized_stream << std::scientific; break; + } + if (isupper(format[0])) { + localized_stream << std::uppercase; + } + if (fill[0] != '\0') { + localized_stream << std::setfill(fill[0]); + } + if (width >= 0) { + localized_stream << std::setw(width); + } + if (precision >= 0) { + localized_stream << std::setprecision(precision); + } + localized_stream << value; + const std::string& tmp = localized_stream.str(); + const char* cstr = tmp.c_str(); + int size = tmp.length()+1; + byte_array* array = allot_byte_array(size); + memcpy(array->data(), cstr, size); ctx->replace(tag(array)); }