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:
| Piszesz | Co się kiedyś działo | Co 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 defined | błąd kompilacji, z podpowiedzią najbliższej skatalogowanej pisowni |
Blorp(1, 2) | przekazywane dosłownie do wygenerowanego JavaScriptu | błąd kompilacji |
ceci nest pas du basic | emitowane jako instrukcja | błą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,
SetMusicSystemVolumeiGetLightSensorExists, które katalog zna tylko jakoMusicSystemVolumeiLightSensorExists.
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.
Print rysuje. Console loguje.#
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, ClearConsole | reszta 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
DIVi 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:
| 3D | 286 | Studio | 106 | File | 61 |
| Core | 200 | Input | 95 | Memblock | 43 |
| Tweening | 149 | Input-Raw | 94 | 3D Particles | 41 |
| 3D Physics | 144 | Multiplayer | 91 | World | 40 |
| Sprite | 135 | Text | 68 | Particles | 38 |
| Platform | 111 | 2D Physics | 66 | Sound | 37 |
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.
Printto 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ć.