BASIC भाषा
aukimi की क्लासिक BASIC डायलेक्ट: टाइप, स्ट्रक्चर, दो शॉर्टहैंड, और वे नियम जो हर किसी को पकड़ लेते हैं। इसके पीछे 2,237 कमांड।
एक लाइन में#
aukimi एक क्लासिक BASIC डायलेक्ट देता है: एक पूरी भाषा, कोई खिलौना
मैक्रो सिस्टम नहीं, टाइप की गई संख्याओं, records, methods, references,
structured errors, coroutines और WebGPU compute के साथ। यह Engine के TXT
व्यूपोर्ट मोड में और script editor के BASIC व्यू में रहता है।
JavaScript ही असली (canonical) scripting API बना रहता है। BASIC एक वैकल्पिक frontend है: दोनों एक ही प्राइवेट dispatcher पर कंपाइल होते हैं, इसलिए कोई BASIC प्रोग्राम और कोई JavaScript प्रोग्राम ठीक उसी इंजन तक पहुँचते हैं। कुछ भी दोयम दर्जे का नहीं है, और कोई अलग runtime नहीं है।
वह नियम जो हर किसी को पकड़ लेता है#
किसी कमांड कॉल में हमेशा parentheses होते हैं।
mode = ClipSpaceMode()
SpritePosition(player, 320, 180)
यह कोई स्टाइल की बात नहीं है। यही वह चीज़ है जो कंपाइलर को किसी कमांड और किसी वेरिएबल में फ़र्क़ करने देती है, और यही वजह है कि अब कोई ग़लत स्पेलिंग कंपाइल टाइम पर ही पकड़ी जाती है:
| आप जो लिखते हैं | पहले क्या होता था | अब क्या होता है |
|---|---|---|
SpritePositon(1, 10, 20) | साफ़-साफ़ कंपाइल हो जाता था, स्प्राइट हिलता नहीं था, और ग़लती बाद में ... is not defined के रूप में सामने आती थी | कंपाइल एरर, कैटलॉग की सबसे नज़दीकी स्पेलिंग सुझाई जाती है |
Blorp(1, 2) | जस-का-तस जनरेट किए गए JavaScript में आगे भेज दिया जाता था | कंपाइल एरर |
ceci nest pas du basic | एक statement के रूप में निकाला जाता था | कंपाइल एरर |
एक लिखने की ग़लती पहले ख़ुद को एक इंजन बग की तरह पेश करती थी। 84-डेमो के कॉर्पस पर मापने पर, गार्ड ने शून्य false positive दिए और दो असली, चुपचाप हुई विफलताएँ ढूँढ निकालीं,
SetMusicSystemVolumeऔरGetLightSensorExists, जिन्हें कैटलॉग सिर्फ़MusicSystemVolumeऔरLightSensorExistsके नाम से जानता है।
दो लीक जान-बूझकर खुले छोड़े गए हैं: console.log("x") और window.x = 1
अब भी पास हो जाते हैं। इनके लिए एक गार्ड लिखा गया, मापा गया, और वापस ले
लिया गया: BASIC एक ऐसे context के अंदर चलता है जो ऐसे नाम देता है जिन्हें
कंपाइलर गिन नहीं सकता, इसलिए किसी अनजान root को अस्वीकार करने से सही
प्रोग्राम भी रिजेक्ट हो जाते थे। वहाँ एक false positive उस लीक से बदतर है।
Print ड्रॉ करता है। Console लॉग करता है।#
सबसे आम हैरानी:
Print(...) | स्क्रीन पर ड्रॉ करता है, और कोई प्रोग्राम इसे हर फ़्रेम में बुलाता है |
Console(...) | editor के console में लिखता है, और बाक़ी कुछ नहीं करता |
Debug(...) | वही कमांड, PureBasic के नाम के साथ, muscle memory के लिए |
ConsoleWarning, ConsoleError, ClearConsole | बाक़ी का लॉग |
किसी frame loop में Print console में किसी भी असली ग़लती को डुबो देगा,
यही वजह है कि ये एक flag वाले एक कमांड की बजाय दो अलग कमांड हैं।
Types#
Numeric types असली हैं, और हर target पर, editor, HTML export और Bevy/native build पर, एक जैसा व्यवहार करते हैं:
- साइन्ड और अनसाइन्ड 8, 16, 32 और 64-बिट इंटिजर, deterministic
coercion, integer
DIV, और wrapping overflow के साथ। - float32 और float64।
- क्लासिक sigil अब भी काम करते हैं:
name$एक string है,speed#एक float।
OPTION EXPLICIT opt-in है, और क्लासिक implicit वेरिएबल डिफ़ॉल्ट बने
रहते हैं ताकि इम्पोर्ट किए गए प्रोग्राम चलते रहें। इसे चालू करना उन दो
फ़ीचर के लिए ज़रूरी शर्त है जो इसके बिना सुरक्षित नहीं हो सकते, numeric
typing और references, क्योंकि कोई ग़लत लिखा गया assignment जो चुपचाप एक
वेरिएबल बना दे, दोनों को बेकार कर देता है।
Structures#
Records#
TYPE एक record को डिक्लेयर करता है। ये मनचाहे तरीक़े से nest हो सकते हैं,
और इनमें value semantics होती है: किसी एक को assign करना उसे nested
arrays और collections सहित deep-copy कर देता है।
Methods#
METHOD किसी function को किसी instance से बाँधता है, अंदर SELF के साथ,
बनाने के लिए New और मिटाने के लिए Delete। Deep copy method-सुरक्षित
बनी रहती हैं।
References#
REF और BYREF दो अलग-अलग स्पेलिंग में एक ही चीज़ हैं, और दोनों एक live
read/write पैरामीटर देते हैं, किसी scalar, record, एक फ़ील्ड, array, list
cursor या map entry के लिए। References calls के आर-पार आगे बढ़ते हैं, और
boundary पर fixed-width types में coerce हो जाते हैं।
Handles#
@target एक first-class reference लेता है। HANDLE और POINTER इसके
टाइप किए गए रूप हैं, checked read, write, validity और release के साथ, और
किसी मिटाए गए record का handle dangling छोड़े जाने के बजाय invalidate कर
दिया जाता है।
Control और safety#
Structured errors: TRY / CATCH / FINALLY, nested, THROW,
protected RETHROW, और structured व string दोनों तरह के catch के साथ।
Conditional compilation: #IF / #ELSEIF / #ELSE / #ENDIF, nested,
feature flags और editor, HTML, Bevy, native/wasm और debug/release के लिए
साफ़ profile के साथ। यह हर target पर includes से पहले resolve होता है।
Rich functions: default values, OPTIONAL, एक आख़िरी PARAMARRAY
(या ...), सुरक्षित arity overload, typed return coercion, और cloned
record व array returns।
मल्टी-फ़ाइल प्रोग्राम#
#INCLUDE, #INSERT और IncludeFile किसी प्रोग्राम को कई फ़ाइलों में
बाँट देते हैं। Editor project modules बनाता और इम्पोर्ट करता है, include
paths पूरे करता है, dependency graph बनाए रखता है, और हर runtime target
इसके लिए तैयार है।
Coroutines, और वह चीज़ जो जान-बूझकर बाहर रखी गई#
Cooperative tasks label-आधारित हैं, typed handles, एक result और error स्थिति, yields पर cancellation, और किसी एक task या group पर await के साथ। ये हर target पर game scheduler साझा करते हैं।
shared memory वाले threads जान-बूझकर बाहर रखे गए हैं। "अभी नहीं" वाले मायने में बाहर नहीं, हमेशा के लिए। एक cooperative scheduler जिसके बारे में आप सोच सकते हैं, किसी ऐसी data race से बेहतर है जिसे आप दोबारा पैदा नहीं कर सकते।
WebGPU compute#
Typed f32 / i32 / u32 storage buffer, raw WGSL pipeline,
frame-ordered dispatch और memblock readback, यानी BASIC से असली GPU
compute।
⚠️ सिर्फ़ Engine। HTML target एक साफ़ capability error देता है, और Bevy target ऐसी binary बनाने के बजाय, जो पहले dispatch पर फेल हो, बिल्ड से पहले असंगति बता देता है।
एक ही समस्या के लिए दो शॉर्टहैंड#
597 कमांड Set/Get<Object><Property> नाम के हैं: Sprite 66, Tween
58, Text 32, Edit 29। ऑब्जेक्ट का नाम function के नाम के अंदर होता है और
उसकी id हर लाइन का पहला argument होती है। नीचे दिए गए दोनों शॉर्टहैंड इस
दोहराव को हटाते हैं, और कोई भी नई API नहीं है: compiler असली कमांड नाम
फिर से बनाता है और उसे कैटलॉग में ढूँढता है।
WITH <family>, किसी block के अंदर#
WITH SPRITE s
\position 100, 200 ` SpritePosition(s, 100, 200)
\size 64, 64 ` SpriteSize(s, 64, 64)
x# = \x ` SpriteX(s)
ENDWITH
किसी statement के सिरे पर \prop लिखता है; बाक़ी हर जगह यह पढ़ता
है। स्थिति ही तय करती है, इसलिए सीखने के लिए कोई दूसरी notation नहीं है।
WITH hero, एक token, अब भी record block है; WITH SPRITE s एक कैटलॉग
family चुनता है।
s.position(...), बाक़ी हर जगह#
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)
Family Create<F> / Load<F> / Clone<F> से आती है, या किसी साफ़
s AS Sprite से जब id कहीं और से आती है। सिर्फ़ वे वेरिएबल दोबारा लिखे
जाते हैं जिनकी family मालूम है: records अपने फ़ील्ड रखते हैं, lists
अपने methods रखती हैं, SELF.field को छुआ नहीं जाता।
⚠️ कोई typed पैरामीटर पहचाना नहीं जाता। FUNCTION move(s AS Sprite),
s को कोई family नहीं देता, यह pass सिर्फ़ statement-level की declaration
और assignment पढ़ता है। यहाँ इसलिए बताया गया है क्योंकि यह एक असली सीमा
है, कोई ऐसा bug नहीं जिसे आप ढूँढें।
⚠️ कैटलॉग properties पर verb हटा देता है, और lifecycle पर उसे रखता है।
SpritePosition लिखता है, SpriteX पढ़ता है, और दोनों में से किसी में
Set या Get नहीं है: पूरे कैटलॉग में सिर्फ़ 4 कमांड Set से शुरू
होते हैं, और कोई भी Get से शुरू नहीं होता। Verb वहाँ बचता है जहाँ
कुछ बनता है या ख़त्म होता है: CreateSprite, LoadImage, DeleteSprite।
यह जानना फ़ायदेमंद है क्योंकि कोई ग़लत स्पेलिंग एक कंपाइल एरर है, और
Set… वह ग़लत स्पेलिंग है जिसके साथ लोग आते हैं। कैटलॉग ही अथॉरिटी है,
और रेफ़रेंस उसी से जनरेट होता है।
String interpolation, opt in#
Print($"score: {points}") ` "score: " + Str(points)
{{ और }} शाब्दिक ब्रेस लिखते हैं।
⚠️ $ prefix ज़रूरी है, और यह सजावट नहीं है। हर literal को
interpolate करना हाथ से लिखे JSON को तोड़ देता था, जिसे world API अक्सर
लेता है:
CreateTerrain("island", "{\"preset\":\"island\",\"size\":256}")
वहाँ ब्रेस डेटा हैं, कोई खाली जगह नहीं। कोई भी बिना prefix वाला string जो भी रखता हो, उसे छुआ नहीं जाता।
नाम देना ही दिखाना है#
कोई क्लासिक प्रोग्राम सैकड़ों ऑब्जेक्ट बनाता है। सिर्फ़ वे ही जिन्हें वह
NAME देता है, Scene Graph में दाख़िल होते हैं, SpriteName(id, "player")
और उसके जैसे बाक़ी कमांड ही किसी ऑब्जेक्ट को उस tree में डालते हैं जहाँ
बाक़ी Engine उसे देख सके। LightName और ParticlesName किसी light और
emitter के लिए वही करते हैं।
Name what your program creates ट्यूटोरियल इसे विस्तार से दिखाता है: वही सीन, एक बार ख़ाली tree के साथ और एक बार उसमें तीन एंट्री के साथ।
कमांड कैटलॉग#
2,237 कमांड, 2,550 पब्लिक overload, 43 कैटेगरी। सबसे बड़ी:
| 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 |
साथ ही 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 और Compute क्लासिक डायलेक्ट में aukimi के अपने जोड़े गए हिस्से हैं, यानी console कमांड, object naming, और WebGPU pipeline।
पूरा कमांड रेफ़रेंस इन सबको सूचीबद्ध करता है, हर पैरामीटर और हर overload के साथ, और अपनी ख़ुद की सर्च के साथ, जो उसी कैटलॉग से जनरेट होती है जिसे यह पेज गिनता है, इसलिए यह कभी उससे पीछे नहीं रह सकता। editor का अपना API पैनल भी वही कैटलॉग पढ़ता है।
यह पेज भाषा को डॉक्यूमेंट करता है; वह पेज कमांड को।
सीमाएँ और आम दिक़्क़तें#
- किसी कमांड पर parentheses वैकल्पिक नहीं हैं। बिना parentheses वाला
PureBasic रूप (
Debug "x") अस्वीकार कर दिया जाता है, क्योंकि यह variable/command वाली वही अस्पष्टता फिर से खोल देता है जिस पर compile-time गार्ड टिका है। - कोई यूज़र function उसी नाम के कैटलॉग वाले कमांड पर भारी पड़ता है, और कोई वेरिएबल किसी typed declaration में, assignment के बाईं ओर, या किसी path की जड़ में, किसी कमांड का नाम साझा कर सकता है।
- वेरिएबल और यूज़र function case-insensitive हैं, और इनकी symbol space सचमुच कैटलॉग की symbol space से अलग है।
Printकोई log नहीं है। ऊपर देखें; यही वह ग़लती है जो किसी console को भर देती है।- Compute एक्सपोर्ट नहीं होता। इस पर भरोसा करने से पहले fallback पाथ लिखें।