Czy parser Haskell powinien dopuszczać cyfry Unicode w literałach numerycznych?

15

Jako ćwiczenie piszę parser Haskella od zera. Tworząc leksyk zauważyłem następujące zasady dotyczące raportu Haskell 2010 :

cyfraascDigit | uniDigit
ascDigit0| 1| … | 9
uniDigit → dowolny Unicode cyfry dziesiętne
octit0| 1| … | 7
hexitcyfra | A| … | F| a| … |f

dziesiętnycyfra { cyfra }
ósemkowyoctit { octit }
szesnastkowyhexit { hexit }

liczba całkowitadziesiętny | 0o ósemkowy | 0O ósemkowy | 0x szesnastkowy | 0X szesnastkowy
pływakdziesiętny . dziesiętny [ wykładnik ] | dziesiętny wykładnik
wykładnik → ( e| E) [ +| -] dziesiętny

Literały dziesiętne i szesnastkowe, wraz z literami zmiennoprzecinkowymi, są oparte na cyfrach , które dopuszczają dowolną cyfrę dziesiętną Unicode, zamiast ascDigit , która dopuszcza tylko podstawowe cyfry 0-9 z ASCII. Co dziwne, ósemkowy jest oparta na octit , który zamiast tylko przyznaje ASCII cyfr 0-7. Domyślam się, że te „cyfry dziesiętne Unicode” są dowolnymi punktami kodowymi Unicode z kategorii ogólnej „Nd”. Obejmuje to jednak takie znaki, jak cyfry pełnej szerokości 0-9 i cyfry Devanagari ०-९. Rozumiem, dlaczego pożądane może być dopuszczenie ich w identyfikatorach, ale nie widzę żadnej korzyści z umożliwienia pisania ९0dla literału 90.

GHC wydaje się ze mną zgadzać. Kiedy próbuję skompilować ten plik,

module DigitTest where
x1 = 

wyrzuca ten błąd.

digitTest1.hs:2:6: error: lexical error at character '\65297'
  |
2 | x1 = 
  |      ^

Jednak ten plik

module DigitTest where
x = 1

kompiluje się dobrze. Czy źle czytam specyfikację języka? Czy zachowanie (rozsądne) GHC jest rzeczywiście prawidłowe, czy technicznie jest niezgodne ze specyfikacją w Raporcie? Nigdzie nie mogę o tym wspominać.

Ian Scherer
źródło
4
Zabawny. Podejrzewam, że stało się tak: „Ok, więc dosłownie składają się z cyfr ASCII, to proste”. „Nie czekaj, pomyślmy o internacjonalizacji, Unicode… mają też inne cyfry, prawda?” „Och tak, eh, nigdy się tym nie zajmowałem ... ale dobrze, wstawmy do tego klauzulę ...” „Świetnie”. ... a potem zostało po prostu zapomniane i nikt tak naprawdę nie zadał sobie trudu, aby go wdrożyć, ani nie zauważył, że nie ma sensu zezwalać na mieszanie różnych rodzin cyfr.
leftaroundabout
Yikes. Tak, nie przejmuj się tym.
Boann

Odpowiedzi:

8

W pliku kodu źródłowego GHC compiler/parser/Lexer.xmożna znaleźć następujący kod:

ascdigit  = 0-9
$unidigit  = \x03 -- Trick Alex into handling Unicode. See [Unicode in Alex].
$decdigit  = $ascdigit -- for now, should really be $digit (ToDo)
$digit     = [$ascdigit $unidigit]
...
$binit     = 0-1
$octit     = 0-7
$hexit     = [$decdigit A-F a-f]
...
@numspc       = _*                   -- numeric spacer (#14473)
@decimal      = $decdigit(@numspc $decdigit)*
@binary       = $binit(@numspc $binit)*
@octal        = $octit(@numspc $octit)*
@hexadecimal  = $hexit(@numspc $hexit)*
@exponent     = @numspc [eE] [\-\+]? @decimal
@bin_exponent = @numspc [pP] [\-\+]? @decimal

Tutaj $decdigitjest używany do analizy literałów dziesiętnych i szesnastkowych (i ich wariantów zmiennoprzecinkowych), natomiast $digitjest używany do „numerycznej” części identyfikatorów alfanumerycznych. Notatka „Do zrobienia” wyjaśnia, że ​​jest to uznane odchylenie GHC od standardu językowego.

Więc czytasz specyfikację poprawnie, a GHC celowo narusza specyfikację. Istnieje otwarty bilet, który sugeruje przynajmniej udokumentowanie odchylenia, ale nie sądzę, aby ktokolwiek wyraził zainteresowanie naprawieniem tego.

KA Buhr
źródło
Wszystkie trzy wymienione tam odchylenia są dość rozsądne. Rozumiem, dlaczego nie ma potrzeby ich „naprawiać”.
Ian Scherer