Przejdź do treści

Typy

Rozdział rozdziela składnię typu, rozpoznawanie jego nazwy i obecną kontrolę zgodności. Przyjęcie typu przez parser lub check nie potwierdza reprezentacji ani poprawnego wykonania na wszystkich targetach.

Składnia

typeReference
    : atomicType (PIPE atomicType)*
    ;
atomicType
    : communicationType
    | mapType
    | genericType
    | arrayType
    | baseType
    ;
baseType
    : INT_TYPE
    | FLOAT_TYPE
    | BOOL_TYPE
    | TEXT_TYPE
    | SYMBOL_TYPE
    | TIME_TYPE
    | DURATION_TYPE
    | IDENTIFIER          // user-defined types + sized types (u8, u32, f64 ...)
    ;
communicationType
    : CHAN    LT typeReference GT
    | QUEUE   LT typeReference GT
    | STREAM  LT typeReference GT
    ;
mapType
    : MAP_TYPE LT typeReference COMMA typeReference GT
    ;
genericType
    : IDENTIFIER LT typeReference (COMMA typeReference)* GT
    ;
arrayType
    : LBRACKET typeReference RBRACKET
    ;

T01 — postacie typu

Postać Struktura zapisu
Int, Float, Bool, Text, Symbol, Time, Duration Typy z osobnymi tokenami gramatyki.
Reading, u8, Uuid Typ nazwany zapisany identyfikatorem.
[T] Typ tablicowy z jednym typem elementu.
Map<K,V> Dwa argumenty: typ klucza i typ wartości.
Name<T,...> Co najmniej jeden argument typu generycznego.
A | B Unia kolejnych typów atomowych.
chan<T>, queue<T>, stream<T> Rodzaj komunikacji i typ elementu.

Unie mogą występować wewnątrz argumentów, np. List<Int | Text>. Pusta lista argumentów generycznych nie jest dozwolona. Gramatyka typu nie daje ogólnego grupowania nawiasami ani dowolnej nazwy kwalifikowanej alias::Typ. Składnia Name<T> nie ustanawia deklaracji własnych parametrów generycznych.

Rozpoznawanie nazw

T02 — nazwy znane analizatorowi

SemanticAnalyzer ma osobny katalog nazw: typy tokenowe, Null, typy liczbowe u8–u64, i8–i64, f32, f64, nazwy Map, List, Option, Result, Bytes, Decimal, Uuid, Json oraz nazwy rodzajów komunikacji. Obecność w tym katalogu nie jest pełnym kontraktem operacji każdego z tych typów.

Pozostałe nazwy są szukane w zakresie typów zadeklarowanych lub importowanych. Nieznany typ nazwany daje E0021 poziomu warning, a nie błąd blokujący. W próbie parametr Missing został przyjęty z tym ostrzeżeniem.

Dla GenericTypeNode walidator przechodzi po argumentach, ale celowo nie sprawdza samej nazwy konstruktora. Unknown<Int> przechodzi próbę bez diagnostyk. Nie dowodzi to istnienia typu Unknown ani obsługi dowolnej liczby argumentów.

T03 — wielkość liter

Gramatyka rozpoznaje tokeny typów w ich zapisanej postaci. Katalog typów wbudowanych i porównanie nazw w TypeEquals nie rozróżniają wielkości liter, podczas gdy zakresy deklaracji i modułów mają własne reguły rozwiązywania nazw. Nie można z tego wyprowadzić jednej ogólnej zasady niewrażliwości języka na wielkość liter; zalecane zapisy pozostają takie jak w tabeli.

Obecna zgodność typów

T04 — porównanie struktury typu

SemanticAnalyzer.TypeEquals wykonuje następujące porównania:

  • typ nazwany: zgodność nazwy bez rozróżniania wielkości liter;
  • typ generyczny: nazwa, liczba argumentów i ich zgodność według pozycji;
  • typ komunikacyjny: ten sam rodzaj i zgodny typ elementu;
  • tablica: zgodny typ elementu;
  • mapa: zgodny typ klucza i wartości;
  • unia: ta sama liczba składników i zgodność składników według pozycji.

Nie jest to ogólny algorytm podtypowania ani dowód równoważności zbiorów unii. Nie normalizuje w tej funkcji kolejności składników ani nie usuwa ich powtórzeń. Nie ustanawia też niejawnej zamiany chan<Int> na stream<Int>, [Int] na List<Int> lub dowolnego składnika na unię.

T05 — jawna adnotacja let

Dla let z jawnym typem analizator porównuje go z typem inicjalizatora, jeżeli udało się ten typ wywnioskować. Niezgodność daje błąd E0044. Brak wywnioskowanego typu nie jest w tej gałęzi dowodem zgodności.

Próby pokazały:

Zapis Wynik check
let value: Int = 1 przyjęte
let value: Int = "text" błąd E0044
let value: Float = 1 błąd E0044
let value: u8 = 300 błąd E0044
let value: Int | Text = 1 błąd E0044
let value: [Int] = [1,2] błąd E0044
let value: List<Int> = [1,2] przyjęte

Błąd dla u8 = 300 nie jest dowodem kontroli zakresu 0–255: w tej próbie nie zgadza się typ adnotacji z typem literału. Podobnie błąd przypisania do unii nie ustanawia kompletnego kontraktu konstruowania i zawężania wartości unijnych. Literał listy jest obecnie wnioskowany jako List<...>; typ tablicowy i generyczny nie są w tym porównaniu utożsamiane.

Null, liczby i ograniczenia dziedzinowe

T06 — Null

Null nie ma osobnego tokenu typu, lecz jest rozpoznawany przez katalog semantyczny. Parametr Text | Null przechodzi próbę bez diagnostyk. To nie dowodzi automatycznej inicjalizacji null, konwersji, bezpiecznego dostępu ani pełnego zawężania unii. Storage ma osobną walidację nullable i nie należy przenosić jej szczególnych gwarancji na wszystkie konstrukcje języka.

T07 — liczby i reprezentacja

Rozmiar i reprezentacja Int, Float, Time i innych kategorii nie wynikają z samego tokenu. Nie utożsamiamy ich automatycznie z typami Go, C++ czy JavaScript. Nazwy liczb o określonym rozmiarze są rozpoznawane, ale samo sprawdzanie nazwy nie potwierdza pełnej kontroli zakresów, przepełnień, zaokrągleń ani konwersji.

T08 — mapa i pozostałe ograniczenia

Map<[Int],Text> przechodzi próbę jako typ parametru. Rekurencyjna walidacja nazw nie ustanawia więc ograniczeń porównywalności lub haszowania klucza we wszystkich wykonawcach. Podobnie składniowa obecność Option<T> i Result<T,...> nie jest dowodem kompletnego modelu obsługi błędów i wartości opcjonalnych. Ograniczenia danego zastosowania, np. przenośne typy storage, są sprawdzane osobno.

Sprawdzone przykłady

Pary są sprawdzane przez rzeczywiste CLI w osobnych projektach. Potwierdzają przyjęcie lub odrzucenie źródła, nie zachowanie wygenerowanego programu.

Przykład poprawny

struct Reading {
    value: Float
    tags: [Text]
}

Kontrola: przykład przyjęty przez check. Nie jest to test wykonania.

Przykład błędny

struct Reading { value: chan<> }

Powód: Typ komunikacyjny wymaga typu elementu.

Kontrola: przykład odrzucony przez check; kody: P0001.

Pełny zakres weryfikacji przykładów.

Przykład: Zgodność jawnej adnotacji let

Poprawny zapis

task Main() @server { let value: Int = 1 }

Kontrola: przykład przyjęty przez check. Nie jest to test wykonania.

Błędny zapis

task Main() @server { let value: Int = "text" }

Powód: Wnioskowany Text nie jest zgodny z deklarowanym Int.

Kontrola: przykład odrzucony przez check; kody: E0044.

Pełny zakres weryfikacji przykładów.

Przykład: Typ elementów tablicy

Poprawny zapis

task Main() @server { let value: List<Int> = [1,2] }

Kontrola: przykład przyjęty przez check. Nie jest to test wykonania.

Błędny zapis

task Main() @server { let value: [Text] = [1,2] }

Powód: Literał [1,2] jest wnioskowany jako List, a nie [Text].

Kontrola: przykład odrzucony przez check; kody: E0044.

Pełny zakres weryfikacji przykładów.

Przykład: Składnia unii

Poprawny zapis

task Main(value: Int | Text) @server {}

Kontrola: przykład przyjęty przez check. Nie jest to test wykonania.

Błędny zapis

task Main(value: Int |) @server {}

Powód: Po separatorze unii wymagany jest kolejny typ.

Kontrola: przykład odrzucony przez check; kody: P0001.

Pełny zakres weryfikacji przykładów.

Jawne luki

  • Pełna walidacja istnienia i liczby argumentów konstruktora typu generycznego.
  • Jednolite diagnozowanie nierozwiązanych typów i przypadków bez ustalonego typu wyrażenia.
  • Kompletny kontrakt konwersji, podtypowania oraz tworzenia i zawężania unii.
  • Spójność typów tablicowych, literałów list i reprezentacji w generatorach.
  • Zakresy liczb, przepełnienia, zaokrąglenia i konwersje na wszystkich targetach.
  • Ograniczenia typów kluczy map i pełne kontrakty kolekcji.
  • Reprezentacja, własność i serializacja typów zewnętrznych oraz wartości złożonych.

Nie uzupełniamy tych reguł zachowaniem pojedynczego języka hosta.

Podstawa w repozytorium

  • grammar/JunexisLang.g4: reguły przytoczone powyżej.
  • compiler/JunexisLang.Compiler.Core/Semantics/SemanticAnalyzer.cs: katalog s_builtinTypes, ValidateTypeRef, TypeEquals, InferExprType oraz sprawdzanie let.
  • compiler/JunexisLang.Compiler.Tests/Semantics/SemanticAnalyzerTests.cs: testy semantyki i typowania wyrażeń.
  • Rozdziały komunikacji, modułów, storage i extern: dodatkowe kontrole właściwe danej granicy.