Limbajul BASIC
Dialectul BASIC clasic al aukimi: tipuri, structuri, cele două prescurtări și regulile care prind pe toată lumea. 2 237 de comenzi în spate.
Într-o propoziție#
Aukimi livrează un dialect BASIC clasic: un limbaj complet, nu un simplu
sistem de macro-uri, cu numerice tipizate, înregistrări, metode, referințe,
erori structurate, corutine și compute WebGPU. Trăiește în modul de viewport
TXT al Engine-ului și în vederea BASIC a editorului de script.
JavaScript rămâne API-ul canonic de scriptare. BASIC este un frontend opțional: amândouă se compilează spre același dispecer privat, așa că un program BASIC și unul JavaScript ajung exact la același motor. Nimic nu este de rang secund, și nimic nu este un runtime separat.
Regula care prinde pe toată lumea#
Un apel de comandă poartă întotdeauna paranteze.
mode = ClipSpaceMode()
SpritePosition(player, 320, 180)
Acesta nu este un stil. Este ceea ce îi permite compilatorului să deosebească o comandă de o variabilă, și de aceea o greșeală de scriere este acum prinsă la compilare:
| Scrii | Ce se întâmpla înainte | Ce se întâmplă acum |
|---|---|---|
SpritePositon(1, 10, 20) | se compila curat, sprite-ul nu se mișca, iar eșecul apărea mai târziu ca ... is not defined | eroare de compilare, cu cea mai apropiată ortografie din catalog sugerată |
Blorp(1, 2) | trimisă mai departe, cuvânt cu cuvânt, în JavaScript-ul generat | eroare de compilare |
ceci nest pas du basic | emisă ca o instrucțiune | eroare de compilare |
O greșeală de scriere se prezenta drept un bug de motor. Măsurat pe corpusul de 84 de demonstrații, garda a produs zero falși pozitivi și a găsit două eșecuri tăcute reale,
SetMusicSystemVolumeșiGetLightSensorExists, pe care catalogul le cunoaște doar caMusicSystemVolumeșiLightSensorExists.
Două scurgeri sunt lăsate deschise intenționat: console.log("x") și
window.x = 1 trec în continuare. O gardă pentru ele a fost scrisă,
măsurată și retrasă: BASIC rulează într-un context care furnizează nume
pe care compilatorul nu le poate enumera, așa că refuzarea unei rădăcini
necunoscute respingea programe valide. Un fals pozitiv acolo este mai rău
decât scurgerea.
Print desenează. Console scrie în jurnal.#
Cea mai frecventă surpriză:
Print(...) | desenează pe ecran, iar un program o apelează în fiecare cadru |
Console(...) | scrie în consola editorului, și nu face nimic altceva |
Debug(...) | aceeași comandă sub numele ei din PureBasic, pentru memoria musculară |
ConsoleWarning, ConsoleError, ClearConsole | restul jurnalului |
Print într-o buclă de cadru ar îneca orice eroare reală în consolă, motiv
pentru care cele două sunt comenzi separate, nu una cu un flag.
Tipuri#
Tipurile numerice sunt reale, și se comportă identic pe fiecare țintă, editorul, exportul HTML și build-ul Bevy/nativ:
- Întregi semnați și nesemnați pe 8, 16, 32 și 64 de biți, cu coerciune
determinată,
DIVîntreg, și overflow prin wrapping. - float32 și float64.
- Sigiliile clasice funcționează în continuare:
name$este un șir,speed#un float.
OPTION EXPLICIT este opțional, iar variabilele implicite clasice rămân
implicite, astfel încât programele importate să ruleze în continuare.
Activarea lui este condiția pentru cele două funcționalități care nu pot fi
sigure fără el, tipizarea numerică și referințele, pentru că o atribuire
greșit scrisă care creează tăcut o variabilă le compromite pe amândouă.
Structuri#
Înregistrări#
TYPE declară o înregistrare. Se pot imbrica arbitrar, și au semantică de
valoare: atribuirea uneia o copiază în profunzime, inclusiv array-urile și
colecțiile imbricate.
Metode#
METHOD leagă o funcție de o instanță, cu SELF în interiorul ei, New
pentru a construi și Delete pentru a distruge. Copiile în profunzime rămân
sigure pentru metode.
Referințe#
REF și BYREF sunt același lucru sub două denumiri, și amândouă dau un
parametru viu, de citire/scriere, pentru un scalar, o înregistrare, un
singur câmp, un array, un cursor de listă sau o intrare de map. Referințele
se transmit prin apeluri și se convertesc la tipuri cu lățime fixă la
graniță.
Handles#
@target ia o referință de prim rang. HANDLE și POINTER sunt formele
tipizate, cu citire, scriere, validitate și eliberare verificate, iar un
handle către o înregistrare ștearsă este invalidat, nu lăsat suspendat.
Control și siguranță#
Erori structurate: TRY / CATCH / FINALLY, imbricate, cu THROW,
RETHROW protejat, și prinderi atât structurate cât și pe șir de caractere.
Compilare condiționată: #IF / #ELSEIF / #ELSE / #ENDIF, imbricate,
cu flaguri de funcționalitate și profiluri explicite pentru editor, HTML,
Bevy, native/wasm și debug/release. Este rezolvată înainte de includeri,
pe fiecare țintă.
Funcții bogate: valori implicite, OPTIONAL, un PARAMARRAY final (sau
...), suprascrieri sigure de aritate, coerciune tipizată a returului, și
returnări de înregistrări și array-uri clonate.
Programe pe mai multe fișiere#
#INCLUDE, #INSERT și IncludeFile fac dintr-un program mai multe
fișiere. Editorul creează și importă module de proiect, completează căile de
includere, ține graful de dependențe, iar fiecare țintă de runtime este
pregătită pentru asta.
Corutine, și lucrul lăsat deliberat pe dinafară#
Task-urile cooperative sunt bazate pe etichete, cu handle-uri tipizate, o stare de rezultat și de eroare, anulare la yield, și așteptări pe un singur task sau pe un grup. Împart același planificator de joc pe fiecare țintă.
Firele cu memorie partajată sunt excluse deliberat. Nu „încă nu", excluse. Un planificator cooperativ pe care îl poți raționa este mai bun decât o cursă de date pe care nu o poți reproduce.
Compute WebGPU#
Buffere de stocare tipizate f32 / i32 / u32, pipeline-uri WGSL brute,
dispatch ordonat pe cadre și readback de memblock, compute GPU real din
BASIC.
⚠️ Doar în Engine. Ținta HTML ridică o eroare explicită de capabilitate, iar ținta Bevy raportează incompatibilitatea înainte de build, nu produce un binar care eșuează la primul dispatch.
Două prescurtări pentru aceeași problemă#
597 din comenzi se numesc Set/Get<Obiect><Proprietate>: Sprite 66,
Tween 58, Text 32, Edit 29. Numele obiectului se află în interiorul numelui
funcției, iar id-ul lui este primul argument al fiecărei linii. Ambele
prescurtări de mai jos elimină acea repetiție, și niciuna nu este un API nou:
compilatorul reconstruiește numele real al comenzii și îl caută în catalog.
WITH <familie>, în interiorul unui bloc#
WITH SPRITE s
\position 100, 200 ` SpritePosition(s, 100, 200)
\size 64, 64 ` SpriteSize(s, 64, 64)
x# = \x ` SpriteX(s)
ENDWITH
La capul unei instrucțiuni \prop scrie; oriunde altundeva citește.
Poziția decide, așa că nu există o a doua notație de învățat. WITH hero, un
singur token, este tot blocul de înregistrare; WITH SPRITE s selectează o
familie din catalog.
s.position(...), peste tot altundeva#
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)
Familia vine din Create<F> / Load<F> / Clone<F>, sau dintr-un s AS Sprite explicit atunci când id-ul sosește din altă parte. Doar variabilele a
căror familie este cunoscută sunt rescrise: înregistrările își păstrează
câmpurile, listele își păstrează metodele, SELF.field rămâne neatins.
⚠️ Un parametru tipizat nu este recunoscut. FUNCTION move(s AS Sprite)
nu îi dă lui s o familie, trecerea citește doar declarații și atribuiri la
nivel de instrucțiune. Precizat aici pentru că este o limită reală, nu un bug
de căutat.
⚠️ Catalogul renunță la verb pe proprietăți, și îl păstrează pe ciclul de
viață. SpritePosition scrie, SpriteX citește, și niciuna nu poartă un
Set sau un Get: 4 comenzi din tot catalogul încep cu Set, și
niciuna nu începe cu Get. Verbul supraviețuiește acolo unde ceva ia
naștere sau se termină: CreateSprite, LoadImage, DeleteSprite.
Asta merită știut pentru că o greșeală de scriere este o eroare de compilare,
iar Set… este greșeala cu care vine lumea. Catalogul este autoritatea, iar
referința este generată din el.
Interpolare de șiruri, opțională#
Print($"score: {points}") ` "score: " + Str(points)
{{ și }} scriu acolade literale.
⚠️ Prefixul $ este obligatoriu, și nu este decorativ. Interpolarea
fiecărui literal strica JSON scris de mână, pe care API-ul de lume îl
folosește curent:
CreateTerrain("island", "{\"preset\":\"island\",\"size\":256}")
Acolo acoladele sunt date, nu goluri. Un șir fără prefix rămâne neatins, indiferent ce conține.
Denumirea este afișarea#
Un program clasic creează sute de obiecte. Doar cele pe care le NUMEȘTE
intră în Scene Graph, SpriteName(id, "player") și frații lui sunt cei
care pun un obiect în arborele unde restul Engine-ului îl poate vedea.
LightName și ParticlesName fac același lucru pentru o lumină și un
emițător.
Tutorialul Denumește ce creează programul tău parcurge asta pas cu pas, aceeași scenă, o dată cu arborele gol și o dată cu trei intrări în el.
Catalogul de comenzi#
2 237 de comenzi, 2 550 de suprascrieri publice, 43 de categorii. Cele mai mari:
| 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 |
plus 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 sunt adăugările proprii ale Aukimi la dialectul clasic: comenzile de consolă, denumirea obiectelor și pipeline-ul WebGPU.
Referința completă de comenzi le listează pe toate, cu fiecare parametru și fiecare suprascriere, și propria căutare, generată din același catalog pe care îl numără această pagină, așa că nu poate rămâne în urma lui. Panoul propriu de API al editorului citește și el acel catalog.
Această pagină documentează limbajul; cealaltă documentează comenzile.
Limite și capcane frecvente#
- Parantezele nu sunt opționale pe o comandă. Forma PureBasic simplă
(
Debug "x") este refuzată, pentru că redeschide ambiguitatea variabilă/comandă de care depinde garda de la compilare. - O funcție de utilizator câștigă în fața unei comenzi din catalog cu același nume, iar o variabilă poate împărți numele unei comenzi într-o declarație tipizată, în stânga unei atribuiri, sau ca rădăcină a unei căi.
- Variabilele și funcțiile de utilizator sunt case-insensitive, iar spațiile lor de simboluri sunt cu adevărat separate de cele ale catalogului.
Printnu este un jurnal. Vezi mai sus; este greșeala care umple o consolă.- Compute nu se exportă. Scrie calea de rezervă înainte să te bazezi pe ea.