Przejdź do treści

Granica zewnętrzna: extern

extern deklaruje granicę z kodem dostarczanym poza Junexis. Należy rozróżnić sygnaturę zadania, nazwę typu zewnętrznego oraz nazwany kontrakt integracji. Ich poprawne sprawdzenie nie dowodzi obecności ani wykonania implementacji natywnej.

Składnia zadania i typu

externDeclaration
    : EXTERN TASK IDENTIFIER
      (LPAREN parameterList? RPAREN)?
      platformAnnotation*
      communicationSignature?
      SEMICOLON?
    ;
externTypeDeclaration
    : EXTERN TYPE IDENTIFIER platformAnnotation+ SEMICOLON?
    ;

E01 — extern task

extern task zawiera nazwę, opcjonalną listę parametrów w nawiasach, zero lub więcej adnotacji platformy oraz opcjonalną sygnaturę wyniku. Średnik jest opcjonalny. Nawiasy można pominąć; nie ma ciała instrukcji Junexis. extern task Read() @server {} jest błędem parsera.

Parametry i wynik podlegają kontroli typów. Sama zgodność typów nie określa mapowania reprezentacji w pamięci, skutków ubocznych ani sposobu zgłaszania błędów. Gramatyka nie wymaga platformy przy extern task; próba bez platformy przechodzi check. Nie jest to dowód wyboru domyślnego wykonawcy.

E02 — extern type

extern type wymaga nazwy oraz co najmniej jednej adnotacji platformy. Nie deklaruje pól ani ich układu. Nie należy utożsamiać go ze strukturą Junexis o dowolnie dostępnych polach, z serializowalną wiadomością ani ze wspólnym ABI wszystkich generatorów. Deklaracja z @server przechodzi sprawdzanie; deklaracja bez platformy jest błędem składni.

Składnia kontraktu

externContractDeclaration
    : EXTERN anyIdentifier anyIdentifier externContractBody
    ;
externContractBody
    : LBRACE externContractMember* RBRACE
    ;
externContractMember
    : externFunctionMember
    | externFileMember
    | externLanguageMember
    | externTargetMember
    ;
externFunctionMember
    : FN IDENTIFIER LPAREN parameterList? RPAREN (ARROW typeReference)? SEMICOLON?
    ;
externTargetMember
    : IDENTIFIER platformTarget SEMICOLON?
    ;
externLanguageMember
    : IDENTIFIER IDENTIFIER SEMICOLON?
    ;
externFileMember
    : IDENTIFIER STRING_LITERAL SEMICOLON?
    ;

E03 — deklaracja granicy

Postać extern rodzaj Nazwa { ... } jest odrębna od pojedynczego extern task. Na przykład extern telemetry Sensor opisuje nazwaną granicę, a nie tworzy automatycznie zadania Sensor. Ciało może być puste. Funkcja kontraktu ma listę parametrów i opcjonalny wynik, lecz nie ma ciała. Zwyczajowe wpisy to:

extern telemetry Sensor {
    target server
    language go
    file "user/server/sensor.go"
    fn read(value: Int) -> Int
}

target nie jest tu adnotacją z @. Wartością jest platformTarget. Język jest identyfikatorem, a ścieżka pliku literałem tekstowym.

E04 — ograniczenie rozpoznawania pól kontraktu

Reguły członków posługują się ogólnym IDENTIFIER w miejscu klucza wpisu. AstBuilder wybiera znaczenie według rozpoznanej postaci członka; nie sprawdza, czy pierwszy identyfikator jest dokładnie słowem target, language albo file. Próba extern telemetry Sensor { mystery go } przechodzi check. Nie stanowi to kontraktu dowolnych rozszerzeń metadanych.

Kolejne rozpoznane wpisy target, języka lub pliku zastępują poprzednią wartość w AST. Powtórzone language go language rust przechodzi sprawdzanie. Nie opisujemy tego jako zalecanej składni ani reguły rozstrzygania konfiguracji; brakuje diagnostyk nieznanych kluczy i powtórzeń.

Wiązanie funkcji z extern task

E05 — konwencja nazwy

SemanticAnalyzer.ValidateExternContractBindings dla funkcji read w kontrakcie Sensor szuka zadania zewnętrznego Sensor_read.

extern task Sensor_read(value: Int) @server -> Int

Brak takiej deklaracji albo znalezienie zwykłego tasku zamiast extern task prowadzi do ostrzeżenia W0030, a nie błędu. Sama funkcja kontraktu nie zastępuje w tej kontroli deklaracji zadania zewnętrznego. Nazwy są wyszukiwane w tablicy symboli; nie jest to sprawdzenie symbolu w pliku Go, C++ ani TypeScript.

E06 — zgodność sygnatury

Jeżeli odpowiadające extern task istnieje, kontrola sprawdza:

  • obecność platformy wskazanej przez target kontraktu, jeżeli target podano;
  • liczbę parametrów i zgodność ich typów według pozycji;
  • zgodność wyniku, w tym jego braku.

Niezgodność powoduje błąd E0031. Platforma jest porównywana bez rozróżniania wielkości liter. Zadanie może mieć dodatkowe adnotacje: ta kontrola wymaga obecności oczekiwanej, nie wyłączności jednej platformy.

Nazwy parametrów nie są w tym porównaniu wymagane jako identyczne. fn read(value: Int) oraz extern task Sensor_read(other: Int) przeszły próbę bez diagnostyk. To zgodność pozycyjnych typów, nie mapowanie argumentów po nazwach między dowolnymi językami hosta.

Sprawdzone przykłady

Pary są sprawdzane przez rzeczywiste CLI w osobnych projektach. Nie dołączają implementacji natywnej i nie są testami działania integracji.

Przykład poprawny

extern task ReadTemperature() @embedded -> Float

task Source() @embedded -> chan<Float> {
    send ReadTemperature()
}

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

Przykład błędny

extern task ReadTemperature(value Float) @embedded -> Float

Powód: Parametr extern task również wymaga dwukropka przed typem.

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

Pełny zakres weryfikacji przykładów.

Przykład: Zgodność sygnatury kontraktu

Poprawny zapis

extern telemetry Sensor { target server language go file "missing.go" fn read(value: Int) -> Int }
extern task Sensor_read(value: Int) @server -> Int

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

Błędny zapis

extern telemetry Sensor { target server language go file "missing.go" fn read(value: Int) -> Int }
extern task Sensor_read(value: Text) @server -> Int

Powód: Typ parametru extern task nie odpowiada typowi funkcji kontraktu.

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

Pełny zakres weryfikacji przykładów.

Przykład: Platforma wiązania

Poprawny zapis

extern telemetry Sensor { target server language go file "missing.go" fn read(value: Int) -> Int }
extern task Sensor_read(value: Int) @server -> Int

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

Błędny zapis

extern telemetry Sensor { target server language go file "missing.go" fn read(value: Int) -> Int }
extern task Sensor_read(value: Int) @report -> Int

Powód: Extern task nie ma platformy server wymaganej przez kontrakt.

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

Pełny zakres weryfikacji przykładów.

Przykład: Typ zewnętrzny wymaga platformy

Poprawny zapis

extern type Handle @server

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

Błędny zapis

extern type Handle

Powód: extern type wymaga co najmniej jednej adnotacji platformy.

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

Pełny zakres weryfikacji przykładów.

Przykład: Deklaracja bez ciała

Poprawny zapis

extern task Read -> Int

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

Błędny zapis

extern task Read() @server {}

Powód: extern task deklaruje sygnaturę, a nie ciało instrukcji Junexis.

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

Pełny zakres weryfikacji przykładów.

Generowanie a dostarczenie implementacji

ExternContractManifestGenerator zapisuje kontrakty do manifestu externs/junexis.externs.toml danego targetu: rodzaj, nazwę, target, język, ścieżkę pliku i sygnatury. Wybiera kontrakty bez targetu albo zgodne z targetem manifestu. Obecność manifestu nie potwierdza dostępności pliku i funkcji.

Generator Go ma ścieżkę emitującą zastępczą funkcję, która przy wywołaniu kończy się panic z komunikatem Junexis extern is not bound. Wygenerowanie takiej funkcji nie oznacza realizacji zadania. Nie rozszerzamy tego zachowania Go na wszystkie generatory.

Repozytorium ma polecenie extern scaffold i testy tworzenia szkieletu Go, pominięcia istniejącego pliku oraz trybu bez zapisu. Szkielet nadal wymaga implementacji. To narzędzie przygotowawcze, nie dowód poprawności integracji. Pliki wskazane przez autora są oddzielone od plików należących do generatora.

Rodzaj extern storage ma dodatkowe ścieżki manifestów i kontraktów storage. Nie jest równoważny deklaracji logicznych encji, query i mutation w storage, ani sam w sobie nie otwiera połączenia z bazą. Nie przenosimy gwarancji szczególnego kontraktu storage na dowolny rodzaj extern.

Wyniki prób granicznych

Próba Wynik check Granica dowodu
Zgodne typy i platforma Sensor_read przyjęte Sprawdzenie deklaracji Junexis, nie implementacji natywnej.
Brak Sensor_read dla funkcji kontraktu przyjęte, W0030 Brak wiązania nie blokuje tej próby.
Inna nazwa parametru przy zgodnym typie przyjęte bez diagnostyk Zgodność typów sprawdzana pozycyjnie.
Niezgodny typ parametru odrzucone, E0031 Kontrola sygnatury jest aktywna.
Brak wymaganej platformy odrzucone, E0031 Kontrola targetu kontraktu jest aktywna.
file "missing.go" w zgodnym kontrakcie przyjęte bez diagnostyk check nie potwierdził istnienia implementacji w tym pliku.
Pusty kontrakt przyjęte Nie ustanawia zachowania integracji.
Nieznany klucz lub powtórzone language przyjęte Brak pełnej walidacji wpisów.

Jawne luki i granice kontraktu

  • Walidacja nazw kluczy, ich powtórzeń, wymaganych pól oraz zgodności języka z targetem.
  • Pełne sprawdzenie istnienia pliku, symbolu natywnego i zgodności jego rzeczywistej sygnatury z deklaracją Junexis na wszystkich targetach.
  • Wspólny kontrakt reprezentacji typów i wartości, własności pamięci, czasu życia uchwytów i zasad zwalniania zasobów.
  • Mapowanie błędów, wyjątków/panic, anulowania i limitów czasu na poziom Junexis.
  • Reguły współbieżnego wywoływania, bezpieczeństwa wątkowego i efektów zewnętrznych.
  • Serializacja i przesyłanie uchwytów między procesami lub urządzeniami.

Są to właściwości wymagające osobnych kontraktów i dowodów. Sam token extern, poprawna sygnatura czy manifest ich nie zapewniają.

Podstawa w repozytorium

  • grammar/JunexisLang.g4: reguły przytoczone powyżej.
  • compiler/JunexisLang.Compiler.Core/Parsing/AstBuilder.cs: VisitExternContractDeclaration, odczyt i zastępowanie pól kontraktu.
  • compiler/JunexisLang.Compiler.Core/Semantics/SemanticAnalyzer.cs: ValidateExternContractBindings i ValidateExternBindingSignature.
  • compiler/JunexisLang.Compiler.CodeGen/ExternContractManifestGenerator.cs i GoCodeGenerator.cs: manifest i zastępcze funkcje.
  • compiler/JunexisLang.Compiler.Tests/Semantics/SemanticAnalyzerTests.cs: testy typów, duplikatów i zgodności kontraktów.
  • compiler/JunexisLang.Compiler.CodeGen.Tests/CodeGeneratorExternContractTests.cs: testy tekstu artefaktów; nie są próbami wykonania kodu natywnego.
  • compiler/JunexisLang.Compiler.CLI.Tests/ExternScaffoldCommandTests.cs: odrębne testy przygotowania plików implementacji.