Short Version
Given:
const
Whitespace = [$0009, $000A, $000C, $0020];
- Works:
if ch in Whitespace then... - Fails:
case ch of Whitespace: ...
Long Version
Normally, if you were to have a case statement, you can include various values for each case, eg:
var
ch: UCS4Char; // unsigned 32-bit
case ch of
48..57: {asciiDigit}; //i.e. '0'..'9'
65..70: {asciiUpperHexDigit}; //i.e. 'A'..'F'
97..102: {asciiLowerHexDigit}; //i.e. 'a'..'f'
end;
That works, but I would like these values to be constants:
const
//https://infra.spec.whatwg.org/#code-points
asciiDigit = [Ord('0')..Ord('9')]; //https://infra.spec.whatwg.org/#ascii-digit
asciiUpperHexDigit = [Ord('A')..Ord('F')]; //https://infra.spec.whatwg.org/#ascii-upper-hex-digit
asciiLowerHexDigit = [Ord('a')..Ord('f')]; //https://infra.spec.whatwg.org/#ascii-lower-hex-digit
asciiHexDigit = asciiUpperHexDigit asciiLowerHexDigit; //https://infra.spec.whatwg.org/#ascii-hex-digit
asciiUpperAlpha = [Ord('A')..Ord('Z')]; //https://infra.spec.whatwg.org/#ascii-upper-alpha
asciiLowerAlpha = [Ord('a')..Ord('z')]; //https://infra.spec.whatwg.org/#ascii-lower-alpha
asciiAlpha = asciiUpperAlpha asciiLowerAlpha; //https://infra.spec.whatwg.org/#ascii-alpha
asciiAlphaNumeric = asciiDigit asciiAlpha; //https://infra.spec.whatwg.org/#ascii-alphanumeric
Is there any arrangement of any syntax that will allow:
caseing aCardinal- against a "set of
Cardinals"?
Or am I permanently stuck with the following?
var
ch: UCS4Char; //unsigned 32-bit
case ch of
Ord('!'): FState := MarkupDeclarationOpenState;
Ord('/'): FState := EndTagOpenState;
Ord('?'): AddParseError('unexpected-question-mark-instead-of-tag-name');
UEOF: AddParseError('eof-before-tag-name parse error');
Whitespace: FState := SharkTankContosoGrobber;
else
if ch in asciiDigit then
begin
FReconsume := True;
FState := tsTagNameState;
end
else
AddParseError('invalid-first-character-of-tag-name parse error');
end;
Obviously, using the conceptual case matches the logic being performed; having to do if-elseif is...lesser.
Note: I don't need it to actually be a Delphi "set", that is a specific term with a specific meaning. I just want:
case ch of Whitespace: ...
to work the same way:
if ch in Whitespace then...
already does work.
And we know the compiler already is OK with comparing a Cardinal to a "set", because the following already works:
case ch of
$000A, $000D, $0009, $0032: ...
end;
It's comparing a Cardinal to a "set of numbers".
Bonus Reading
- Delphi case statement for integer ranges
- Efficiently compare an integer against a static list of integers in Delphi?
- any way to compare an integer variable to a list of integers in if statement
- What Delphi type for 'set of integer'?
CodePudding user response:
No, this is not supported.
According to the official documentation:
A case statement has the form:
case selectorExpression of caseList1: statement1; ... caseListn: statementn; endwhere [...] each
caseListis one of the following:
- A numeral, declared constant, or other expression that the compiler can evaluate without executing your program. It must be of an ordinal type compatible with
selectorExpression. [...]- A subrange having the form
First..Last, whereFirstandLastboth satisfy the criterion above andFirstis less than or equal toLast.- A list having the form
item1, ..., itemn, where each item satisfies one of the criteria above.
Hence, this only allows single values, explicit ranges, and lists of such values, as part of the case syntax.
Although the Delphi documentation is good, it isn't perfect and you cannot rely on it to 100%. However, I'm sure all experienced Delphi developers will agree that a caseList cannot be a predeclared single-identifier "collection" of ordinal values compatible with selectorExpression.
You may file a feature request at Embarcadero's Jira.
But you can use the range syntax and a previously declared subrange type (not set constant) to achieve something partly similar:
type
TAsciiDigit = '0'..'9';
TAsciiLatinCapitalLetter = 'A'..'Z';
TAsciiLatinSmallLetter = 'a'..'z';
procedure TForm1.FormCreate(Sender: TObject);
begin
var c := 'R';
case c of
Low(TAsciiDigit) .. High(TAsciiDigit):
ShowMessage('Digit!');
Low(TAsciiLatinCapitalLetter) .. High(TAsciiLatinCapitalLetter):
ShowMessage('Capital!');
Low(TAsciiLatinSmallLetter) .. High(TAsciiLatinSmallLetter):
ShowMessage('Small letter!');
else
ShowMessage('Something else.');
end;
end;
Bonus remark: In fact, the non-100% accuracy of the documentation can be seen in the section quoted above:
selectorExpressionis any expression of an ordinal type smaller than 32 bits
That's nonsense. selectorExpression certainly can be a 32-bit integer.
