The different processing is necessary because ! can be a method:
$ irb
>> class A; def !; true; end; end
=> :!
>> a=A.new
=> #<0x005598bfe61bf0>
>> if !a then "then" else "else" end
=> "then"
>> if a then "then" else "else" end
=> "then"
>> unless a then "then" else "else" end
=> "else"
0x005598bfe61bf0>
The different processing is necessary because
!can be a method:Don’t do this.
Aaron Patterson gave a talk at RubyConf last year that talks a bit more about the internals if you’re interested in learning more.