[MacRuby-devel] [MacRuby] #159: "%d" with large integer argument gives conversion error
MacRuby
ruby-noreply at macosforge.org
Fri Dec 11 18:00:42 PST 2009
#159: "%d" with large integer argument gives conversion error
---------------------------------+------------------------------------------
Reporter: jamis@… | Owner: lsansonetti@…
Type: defect | Status: new
Priority: major | Milestone:
Component: MacRuby | Keywords:
---------------------------------+------------------------------------------
Comment(by emoy@…):
(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/>
More information about the MacRuby-devel
mailing list