Język BASIC

Klasyczny dialekt BASIC aukimi: typy, struktury, dwa skróty i reguły, które łapią każdego. Za nim stoi 2237 poleceń.

W jednym zdaniu#

aukimi dostarcza dialekt klasycznego BASIC: pełny język, nie zabawkowy system makr, z typowanymi liczbami, rekordami, metodami, referencjami, strukturalnymi błędami, koprogramami i WebGPU compute. Mieszka w trybie viewportu TXT w Engine oraz w widoku BASIC edytora skryptów.

JavaScript pozostaje kanonicznym API skryptowym. BASIC to opcjonalny frontend: oba kompilują się do tego samego prywatnego dispatchera, więc program BASIC i program JavaScript trafiają dokładnie do tego samego silnika. Nic nie jest drugiej kategorii i nic nie jest osobnym runtime'em.

Reguła, która łapie każdego#

Wywołanie polecenia zawsze niesie nawiasy.

mode = ClipSpaceMode()
SpritePosition(player, 320, 180)

To nie kwestia stylu. To właśnie pozwala kompilatorowi odróżnić polecenie od zmiennej, i dlatego literówka jest teraz wyłapywana na etapie kompilacji:

PiszeszCo się kiedyś działoCo się dzieje teraz
SpritePositon(1, 10, 20)kompilowało się bez problemu, sprite się nie ruszał, a błąd wychodził później jako ... is not definedbłąd kompilacji, z podpowiedzią najbliższej skatalogowanej pisowni
Blorp(1, 2)przekazywane dosłownie do wygenerowanego JavaScriptubłąd kompilacji
ceci nest pas du basicemitowane jako instrukcjabłąd kompilacji

Błąd pisowni kiedyś udawał błąd silnika. Zmierzone na korpusie 84 dem, zabezpieczenie wyprodukowało zero fałszywych alarmów i znalazło dwa prawdziwe ciche niepowodzenia, SetMusicSystemVolume i GetLightSensorExists, które katalog zna tylko jako MusicSystemVolume i LightSensorExists.

Dwa przecieki zostały celowo zostawione otwarte: console.log("x") i window.x = 1 wciąż przechodzą. Zabezpieczenie dla nich zostało napisane, zmierzone i wycofane: BASIC działa wewnątrz kontekstu, który dostarcza nazwy, jakich kompilator nie potrafi wyliczyć, więc odrzucanie nieznanego korzenia odrzucało też poprawne programy. Fałszywy alarm jest tu gorszy niż sam przeciek.

Najczęstsza niespodzianka:

Print(...)rysuje na ekranie, i program wywołuje je co klatkę
Console(...)zapisuje do konsoli edytora i nie robi nic więcej
Debug(...)to samo polecenie pod nazwą z PureBasic, dla pamięci mięśniowej
ConsoleWarning, ConsoleError, ClearConsolereszta logu

Print w pętli klatek zatopiłby każdy prawdziwy błąd w konsoli, i dlatego to dwa osobne polecenia, a nie jedno z flagą.

Typy#

Typy liczbowe są prawdziwe i zachowują się identycznie na każdym celu: w edytorze, w eksporcie HTML i w buildzie Bevy/natywnym:

  • Podpisane i niepodpisane liczby całkowite 8, 16, 32 i 64-bitowe, z deterministyczną koercją, całkowitoliczbowym DIV i zawijającym przepełnieniem.
  • float32 i float64.
  • Klasyczne sigile wciąż działają: name$ to string, speed# to float.

OPTION EXPLICIT jest opcjonalny, a klasyczne zmienne niejawne pozostają domyślne, więc importowane programy wciąż działają. Włączenie go jest warunkiem dla dwóch funkcji, które bez niego nie mogą być bezpieczne: typowania liczbowego i referencji, ponieważ błędnie napisane przypisanie po cichu tworzące nową zmienną unieważnia obie.

Struktury#

Rekordy#

TYPE deklaruje rekord. Zagnieżdżają się dowolnie i mają semantykę wartościową: przypisanie jednego kopiuje go głęboko, razem z zagnieżdżonymi tablicami i kolekcjami.

Metody#

METHOD wiąże funkcję z instancją, z SELF wewnątrz niej, New do konstruowania i Delete do niszczenia. Głębokie kopie pozostają bezpieczne dla metod.

Referencje#

REF i BYREF to ta sama rzecz pod dwoma nazwami, i oba dają żywy parametr do odczytu i zapisu: dla skalara, rekordu, pojedynczego pola, tablicy, kursora listy albo wpisu mapy. Referencje propagują się przez wywołania i są koercowane do typów o stałej szerokości na granicy.

Uchwyty#

@target bierze referencję pierwszej klasy. HANDLE i POINTER to typowane formy, ze sprawdzanym odczytem, zapisem, ważnością i zwalnianiem, a uchwyt do usuniętego rekordu jest unieważniany, zamiast zostać wiszącym.

Kontrola i bezpieczeństwo#

Strukturalne błędy: TRY / CATCH / FINALLY, zagnieżdżone, z THROW, chronionym RETHROW, oraz przechwytywaniem zarówno strukturalnym, jak i po ciągu znaków.

Kompilacja warunkowa: #IF / #ELSEIF / #ELSE / #ENDIF, zagnieżdżona, z flagami funkcji i jawnymi profilami dla edytora, HTML, Bevy, native/wasm i debug/release. Jest rozwiązywana przed include'ami, na każdym celu.

Bogate funkcje: wartości domyślne, OPTIONAL, końcowy PARAMARRAY (albo ...), bezpieczne przeciążenia liczby argumentów, typowana koercja typu zwracanego oraz klonowane zwroty rekordów i tablic.

Programy wieloplikowe#

#INCLUDE, #INSERT i IncludeFile rozbijają program na kilka plików. Edytor tworzy i importuje moduły projektu, uzupełnia ścieżki include, utrzymuje graf zależności, a każdy cel uruchomieniowy jest do tego przygotowany.

Koprogramy, i rzecz celowo pominięta#

Zadania kooperacyjne są oparte na etykietach, z typowanymi uchwytami, stanem wyniku i błędu, anulowaniem przy yieldach i oczekiwaniem (await) na jedno zadanie albo na grupę. Współdzielą harmonogram gry na każdym celu.

Wątki ze współdzieloną pamięcią są wykluczone celowo. Nie „jeszcze nie”, tylko wykluczone. Harmonogram kooperacyjny, który da się ogarnąć rozumem, bije wyścig danych, którego nie da się odtworzyć.

WebGPU compute#

Typowane bufory pamięciowe f32 / i32 / u32, surowe potoki WGSL, dispatch uporządkowany według klatek i odczyt zwrotny memblock: prawdziwe obliczenia GPU z poziomu BASIC.

⚠️ Tylko Engine. Cel HTML zgłasza jawny błąd braku możliwości, a cel Bevy raportuje niezgodność przed buildem, zamiast produkować binarkę, która zawiedzie przy pierwszym dispatchu.

Dwa skróty na ten sam problem#

597 poleceń nosi nazwę Set/Get<Object><Property>: Sprite 66, Tween 58, Text 32, Edit 29. Nazwa obiektu siedzi wewnątrz nazwy funkcji, a jej id jest pierwszym argumentem każdej linii. Oba skróty poniżej usuwają to powtórzenie, i żaden z nich nie jest nowym API: kompilator odbudowuje prawdziwą nazwę polecenia i wyszukuje ją w katalogu.

WITH <family>, wewnątrz bloku#

WITH SPRITE s
  \position 100, 200      ` SpritePosition(s, 100, 200)
  \size 64, 64            ` SpriteSize(s, 64, 64)
  x# = \x                 ` SpriteX(s)
ENDWITH

Na początku instrukcji \prop zapisuje; wszędzie indziej odczytuje. Pozycja decyduje, więc nie ma drugiej notacji do nauczenia. WITH hero, jeden token, to wciąż blok rekordu; WITH SPRITE s wybiera rodzinę z katalogu.

s.position(...), wszędzie indziej#

s = CreateSprite(img)     ` the family is DEDUCED from the creation command
s.position(100, 200)      ` SpritePosition(s, 100, 200)
s.visible = 1             ` SpriteVisible(s, 1)
x# = s.x                  ` SpriteX(s)

Rodzina pochodzi z Create<F> / Load<F> / Clone<F>, albo z jawnego s AS Sprite, gdy id przychodzi skądinąd. Przepisywane są tylko zmienne, których rodzina jest znana: rekordy zachowują swoje pola, listy zachowują swoje metody, SELF.field pozostaje nietknięte.

⚠️ Typowany parametr nie jest rozpoznawany. FUNCTION move(s AS Sprite) nie nadaje s rodziny, przebieg czyta tylko deklaracje i przypisania na poziomie instrukcji. Napisane tu wprost, bo to prawdziwe ograniczenie, a nie błąd, na który warto polować.

⚠️ Katalog upuszcza czasownik przy właściwościach, a zachowuje go przy cyklu życia. SpritePosition zapisuje, SpriteX odczytuje, i żadne z nich nie niesie Set ani Get: 4 polecenia w całym katalogu zaczynają się od Set, a żadne nie zaczyna się od Get. Czasownik przetrwa tam, gdzie coś powstaje albo się kończy: CreateSprite, LoadImage, DeleteSprite.

Warto to wiedzieć, bo literówka to błąd kompilacji, a Set… to literówka, z którą ludzie przychodzą. Katalog jest autorytetem, a materiał referencyjny jest z niego generowany.

Interpolacja ciągów, opcjonalnie#

Print($"score: {points}")        ` "score: " + Str(points)

{{ i }} zapisują dosłowne nawiasy klamrowe.

⚠️ Prefiks $ jest obowiązkowy i to nie jest ozdobnik. Interpolowanie każdego literału psuło ręcznie pisany JSON, który API świata przyjmuje rutynowo:

CreateTerrain("island", "{\"preset\":\"island\",\"size\":256}")

Tam nawiasy klamrowe to dane, nie otwory na wartości. Ciąg bez prefiksu pozostaje nietknięty, cokolwiek zawiera.

Nazwanie to pokazanie#

Klasyczny program tworzy setki obiektów. Tylko te, które NAZWIE, trafiają do Scene Graph, SpriteName(id, "player") i jego odpowiedniki to właśnie to, co umieszcza obiekt w drzewie, gdzie widzi go reszta Engine. LightName i ParticlesName robią to samo dla światła i emitera.

Tutorial Nazwij to, co tworzy twój program przeprowadza przez to krok po kroku: ta sama scena, raz z pustym drzewem i raz z trzema wpisami w nim.

Katalog poleceń#

2237 polecenia, 2550 publicznych przeciążeń, 43 kategorie. Największe:

3D286Studio106File61
Core200Input95Memblock43
Tweening149Input-Raw943D Particles41
3D Physics144Multiplayer91World40
Sprite135Text68Particles38
Platform1112D Physics66Sound37

Do tego: JSON (36), Image (35), Skeleton (34), XML (34), Music (29), Preference (27), Extras (21), HTTP (21), String (21), Math (19), Regular Expression (19), Video (18), Dictionary (17), Benchmarking (15), Compute (14), Date (13), Maths (12), Time (12), StringBuilder (9), Compression (7), Font (8), Error (4), Array (3), Cipher (2), Sort (2).

Studio i Compute to własne dodatki aukimi do klasycznego dialektu: polecenia konsoli, nazywanie obiektów i potok WebGPU.

Kompletny materiał referencyjny poleceń wymienia je wszystkie, z każdym parametrem i każdym przeciążeniem, oraz własną wyszukiwarką, wygenerowaną z tego samego katalogu, który liczy ta strona, więc nie może się za nim spóźnić. Własny panel API edytora też czyta ten katalog.

Ta strona dokumentuje język; tamta dokumentuje polecenia.

Ograniczenia i częste problemy#

  • Nawiasy przy poleceniu nie są opcjonalne. Goła forma z PureBasic (Debug "x") jest odrzucana, bo na nowo otwiera niejednoznaczność zmienna/polecenie, na której opiera się zabezpieczenie kompilacji.
  • Funkcja użytkownika wygrywa ze skatalogowanym poleceniem o tej samej nazwie, a zmienna może dzielić nazwę z poleceniem w typowanej deklaracji, po lewej stronie przypisania, albo jako korzeń ścieżki.
  • Zmienne i funkcje użytkownika nie rozróżniają wielkości liter, a ich przestrzenie symboli są faktycznie osobne od przestrzeni katalogu.
  • Print to nie log. Patrz wyżej; to błąd, który zapełnia konsolę.
  • Compute się nie eksportuje. Napisz ścieżkę zapasową, zanim zaczniesz na nim polegać.