#159: "%d" with large integer argument gives conversion error ---------------------------------+------------------------------------------ Reporter: ja...@… | Owner: lsansone...@… Type: defect | Status: new Priority: major | Milestone: Component: MacRuby | Keywords: ---------------------------------+------------------------------------------
Comment(by e...@…): (Splitting into 3 parts) Part 1 of 3 The problem is that the MacRuby version of sprintf eventually calls CFStringCreateWithFormat (which is actually wrong, since the resulting string is immutable, but that is a secondary issue). Since CFStringCreateWithFormat know nothing of Bignums, it can never convert them directly. So the most immediate fix would be to do the integer convertion (handling either Fixnums or Bignums) and pass the resulting string to CFStringCreateWithFormat for output. Well, it turns out to not be so simple. Doing this means that we have to interpret most of the format specifier flags (all except '-') and deal with the precision (and with width when precision is unspecified and certain flags are used). So we have to parse the entire format specifier, but this has the advantage that we can generate appropriate error exceptions (the existing sprintf does minimal error checking, and the call to CFStringCreateWithFormat provides no further error diagnosis). Since the goal is to make the MacRuby sprintf work like a standard ruby one, the error messages should likewise be consistent. This turned out to be rather problematic, since that consistency imposes lots of ordering constraints on what gets checked and when. Another tedious issue was the support of the infinite precision representations, like: printf "%x", -1 #=> ..f I hooked into the Fixnum and Bignum code to generate hex, octal or binary representations, then manipulated the string to get the correct result. But after many iterations, and using a test program that reproduced the 68 examples from the sprintf source file, plus a few hundred other test cases (many error cases), I finally had a version that produced the same (if not sometimes confusing or poorly worded) error messages as in ruby 1.9.1. OK, not quite the same. Some error message mentioned NSMutableString or NSArray instead of just plain String or Array. I've always thought that the principle of least astonishment should mean that: % macruby -e 'puts String.new.class' should be "String", but it is currently "NSMutableString". It is a four line change, one line for each of array.c, hash.c, object.c and string.c to get them to print the standard ruby type, and not the Objective-C type (I attach those diffs as pola.diff). I also noticed that the compiler uses StringValueCStr() to convert from ruby object to c-string, but StringValueCStr() calls to_str, which is technically incorrect. So I changed it to call rb_obj_as_string(), which uses to_s. However, some inconsistencies remained. Some are fundament to the underlying CoreFoundation/Objective-C infrastructure, like no null characters in strings. But because we still call CFStringCreateWithFormat, any issues due to type conversion is necessarily handled after other error checking, so: printf "%s %z\n", BasicObject.new, 2 produces: undefined method `to_s' for #<BasicObject:0x0000010083d900> (NoMethodError) by ruby 1.9, but produces: malformed format string - %z (ArgumentError) in MacRuby, because the attempt to call to_s is delayed until the rest of the string is error checked. (As another side issue, replacing %z with the legal%d will cause MacRuby to crash, since BasicObject doesn't have respond_to? either, which the lack of causes infinite recursion and eventual stack exhaustion. This is fixed with a small change to dispatcher.cpp, using a new variable that gets defined in vm_method.c.) To extend test coverage, I modified my test program to automatically generate more cases, expanding to character, float and string conversion, and using all combinations and orders of flags, plus different widths, precisions and values. Then I discovered some new issues. The '0' flag applies to all conversion in C-standard printf routines like CFStringCreateWithFormat, but in ruby, '0' only applies to numeric conversion. I could go ahead and special case that, but I couldn't help expecting more such special casing in the volumes test output differences. (Continued...) -- Ticket URL: <http://www.macruby.org/trac/ticket/159#comment:3> MacRuby <http://macruby.org/> _______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel