I would vote for option
d) Disallow it altogether since it's completely ambiguous and *require* the use of #or:/bitOr: or #and:/bitAnd:. I.e.,
CCodeGenerator>>generateAmbigousOr: msgNode on: aStream indent: level
self error: 'Usage of | is ambiguous - use #or: or #bitOr: instead'.
There are only a handful of uses that need to be fixed and the above would find them very quickly.
Cheers, - Andreas
On 1/11/2011 12:00 PM, Eliot Miranda wrote:
Hi All,
I just got bittenhard (not for the first time) by & and |
(implemented both by integers and booleans) being translated into && (== and:) and || (== or:). So the following in constant folding in the StackToRegisterMappingCogit
(argIsInt and: [rcvrIsInt]) ifTrue: [rcvrInt := objectMemory integerValueOf: rcvrInt. argInt := objectMemory integerValueOf: argInt. primDescriptor opcode caseOf: { [AddRR]-> [result := rcvrInt + argInt]. [SubRR]-> [result := rcvrInt - argInt]. [AndRR]-> [result := rcvrInt &: argInt]. [OrRR]-> [result := rcvrInt | argInt] }. (objectMemory isIntegerValue: result) ifTrue: ["Must annotate the bytecode for correct pc mapping." self annotateBytecode: self Label. ^self ssPop: 2; ssPushConstant: (objectMemory integerObjectOf: result)]. ^self genSpecialSelectorSend].
produced valid results in the simulator, but was translated to
if (argIsInt
&& (rcvrIsInt)) { rcvrInt = (rcvrInt >> 1); argInt = (argInt >> 1);
switch ((primDescriptor->opcode)) { case AddRR: result = rcvrInt + argInt; break; case SubRR: result = rcvrInt - argInt; break; case AndRR: result = rcvrInt && argInt; break; case OrRR: result = rcvrInt || argInt; break; default: error("Case not found and no otherwise clause"); } if (isIntegerValue(result)) { annotateBytecode(gLabel()); return ssPop(2),ssPushConstant(((result << 1) | 1)); } return genSpecialSelectorSend(); }
and so e.g. 16r4000 bitOr: 16r8000 evaluated to 1, not 49152.
Three approaches come to mind, a) emit a warning when & and | are used with variables and/or literals as opposed to message sends, e.g. warn for 1 | 2, var | var et al, but not for (a > b) | (b > c) et al b) translate | to | and & to & c) translate expr | expr to expr || expr and expr & expr to expr && expr, but translate varOrLiteral | anything to varOrLiteral | anything and varOrLiteral & anything to varOrLiteral & anything, and vice verse.
I'm for b) since a relational expression such as a > 1 is defined in C to be either 1 or 0, and so in C (oneOrZero | oneOrZero) == (oneOrZero || oneOrZero) and (oneOrZero & oneOrZero) == (oneOrZero && oneOrZero).
Thoughts, opinions?
best (hurting), Eliot