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(...)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 कैटेगरी। सबसे बड़ी:

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

साथ ही 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 पाथ लिखें।