fix(const): accept hex/octal/binary literals in array-const elements (#129)
$hex, %binary and &octal integer literals were rejected inside an array-constant initialiser — 'array[0..1] of Int64 = ($1, $2)' failed with 'Cannot resolve array-const element' while the scalar form '= $1' worked. The parser stores array elements verbatim (prefix and all), and ResolveConstArrayElem only recognised decimal digits, so any radix-prefixed element fell through to an identifier lookup and errored. Fold radix-prefixed elements (with optional leading sign) through ParseIntLiteral — the same canonical parser the rest of the compiler uses for scalar and typed consts — so all four radixes, plus underscore digit separators, behave identically inside an array initialiser. Keeps FPC's &-octal (the project prefers FPC syntax where FPC and Delphi diverge; the lexer already tokenised all four radixes). Documents the radix-prefix rule in language-rationale.adoc.
This commit is contained in:
parent
fe4e5602cf
commit
5b5b95c18f
|
|
@ -4008,6 +4008,18 @@ var
|
|||
begin
|
||||
Result := AElem;
|
||||
if AElem = '' then Exit;
|
||||
{ Radix-prefixed integer literal — $hex, %binary, &octal (with optional
|
||||
leading sign). The lexer keeps the prefixed form in the token text, but
|
||||
the rest of the const-array pipeline (codegen, OPDF) expects a plain
|
||||
decimal string. Fold through ParseIntLiteral, the same canonical parser
|
||||
the parser uses for scalar/typed consts, so all three radixes behave
|
||||
identically inside an array initialiser. }
|
||||
if AElem[0] = '$' then Exit(IntToStr(ParseIntLiteral(AElem)));
|
||||
if AElem[0] = '%' then Exit(IntToStr(ParseIntLiteral(AElem)));
|
||||
if AElem[0] = '&' then Exit(IntToStr(ParseIntLiteral(AElem)));
|
||||
if (Length(AElem) > 1) and (AElem[0] = '-') and
|
||||
((AElem[1] = '$') or (AElem[1] = '%') or (AElem[1] = '&')) then
|
||||
Exit(IntToStr(-ParseIntLiteral(StrCopyTail(AElem, 1))));
|
||||
{ Already a numeric literal (int, negative int, or float) — leave as is. }
|
||||
if IsPlainInt(AElem) then Exit;
|
||||
if (AElem[0] >= '0') and (AElem[0] <= '9') then Exit;
|
||||
|
|
|
|||
|
|
@ -583,6 +583,32 @@ The bit pattern is preserved in every case; the literal type only
|
|||
selects which signed/unsigned interpretation the surrounding expression
|
||||
sees.
|
||||
|
||||
==== Radix prefixes
|
||||
|
||||
Integer literals may be written in four radixes, following FPC (not
|
||||
Delphi):
|
||||
|
||||
* decimal — `42`
|
||||
* hexadecimal — `$2A` (also Delphi)
|
||||
* binary — `%101010` (Delphi 11+ also accepts this)
|
||||
* octal — `&52` (FPC only; Delphi has never supported octal — there `&`
|
||||
is the identifier-escape prefix)
|
||||
|
||||
Underscore digit separators are permitted in any radix (`$FF_FF`,
|
||||
`%1010_1010`). All four forms are accepted everywhere an integer literal
|
||||
is — scalar and typed constants, expressions, static-array bounds, and
|
||||
*array-constant element lists*. The last was the gap behind issue #129:
|
||||
`array[0..1] of Int64 = ($1, $2)` rejected the hex elements while the
|
||||
scalar form `= $1` accepted them. Array-constant elements now fold
|
||||
through the same `ParseIntLiteral` radix parser the rest of the compiler
|
||||
uses, so every radix behaves identically inside an initialiser.
|
||||
|
||||
The decision to keep FPC's `&` octal (rather than Delphi's no-octal /
|
||||
`&`-as-escape) follows the project rule of preferring FPC syntax where the
|
||||
two dialects diverge; the lexer already tokenised all four radixes, so the
|
||||
fix only made the array-constant path consistent with the rest of the
|
||||
language.
|
||||
|
||||
==== Built-in constant
|
||||
|
||||
`MaxInt: Integer = 2147483647` is a compiler built-in constant. It
|
||||
|
|
|
|||
Loading…
Reference in a new issue