स्टारलार्क भाषा

इस पेज पर, Starlark के बारे में खास जानकारी दी गई है. इसे पहले Skylark के नाम से जाना जाता था. यह Bazel में इस्तेमाल की जाने वाली भाषा है. फ़ंक्शन और टाइप की पूरी सूची देखने के लिए, Bazel API का संदर्भ देखें.

भाषा के बारे में ज़्यादा जानने के लिए, Starlark की GitHub रिपॉज़िटरी देखें.

Starlark सिंटैक्स और इसके काम करने के तरीके के बारे में आधिकारिक जानकारी के लिए, Starlark Language Specification देखें.

सिंटैक्स

Starlark का सिंटैक्स, Python3 से प्रेरित है. Starlark में यह मान्य सिंटैक्स है:

def fizz_buzz(n):
  """Print Fizz Buzz numbers from 1 to n."""
  for i in range(1, n + 1):
    s = ""
    if i % 3 == 0:
      s += "Fizz"
    if i % 5 == 0:
      s += "Buzz"
    print(s if s else i)

fizz_buzz(20)

Starlark का सिमैंटिक, Python से अलग हो सकता है. हालांकि, व्यवहार में बहुत कम अंतर होता है. ऐसा सिर्फ़ उन मामलों में होता है जहां Starlark कोई गड़बड़ी देता है. ये Python टाइप इस्तेमाल किए जा सकते हैं:

बदलाव की क्षमता

Starlark में चीज़ों को बिना बदले रखने पर ज़्यादा ज़ोर दिया जाता है. बदले जा सकने वाले दो डेटा स्ट्रक्चर उपलब्ध हैं: lists और dicts. बदले जा सकने वाले डेटा-स्ट्रक्चर में किए गए बदलाव, सिर्फ़ मौजूदा कॉन्टेक्स्ट में बनाए गए ऑब्जेक्ट के लिए मान्य होते हैं. जैसे, किसी सूची में वैल्यू जोड़ना या किसी डिक्शनरी में एंट्री मिटाना. किसी कॉन्टेक्स्ट के खत्म होने के बाद, उसकी वैल्यू में बदलाव नहीं किया जा सकता.

ऐसा इसलिए होता है, क्योंकि Bazel बिल्ड में काम एक साथ किया जाता है. बिल्ड के दौरान, हर .bzl फ़ाइल और हर BUILD फ़ाइल को अपना एक्ज़ीक्यूशन कॉन्टेक्स्ट मिलता है. हर नियम का विश्लेषण, उसके कॉन्टेक्स्ट के हिसाब से भी किया जाता है.

आइए, फ़ाइल foo.bzl के ज़रिए एक उदाहरण समझते हैं:

# `foo.bzl`
var = [] # declare a list

def fct(): # declare a function
  var.append(5) # append a value to the list

fct() # execute the fct function

Bazel, foo.bzl लोड होने पर var बनाता है. इसलिए, var, foo.bzl के कॉन्टेक्स्ट का हिस्सा है. जब fct() चलता है, तो यह foo.bzl के कॉन्टेक्स्ट में ऐसा करता है. foo.bzl के लिए आकलन पूरा होने के बाद, एनवायरमेंट में एक ऐसी एंट्री var होती है जिसमें बदलाव नहीं किया जा सकता. इसकी वैल्यू [5] होती है.

जब कोई दूसरा bar.bzl, foo.bzl से सिंबल लोड करता है, तो लोड की गई वैल्यू में बदलाव नहीं किया जा सकता. इस वजह से, bar.bzl में मौजूद यह कोड मान्य नहीं है:

# `bar.bzl`
load(":foo.bzl", "var", "fct") # loads `var`, and `fct` from `./foo.bzl`

var.append(6)  # runtime error, the list stored in var is frozen

fct()          # runtime error, fct() attempts to modify a frozen list

bzl फ़ाइलों में तय किए गए ग्लोबल वैरिएबल को, उन्हें तय करने वाली bzl फ़ाइल के बाहर नहीं बदला जा सकता. ऊपर दिए गए उदाहरण में bzl फ़ाइलों का इस्तेमाल किया गया है. इसी तरह, नियमों से मिली वैल्यू में बदलाव नहीं किया जा सकता.

BUILD और .bzl फ़ाइलों के बीच अंतर

BUILD फ़ाइलें, नियमों को कॉल करके टारगेट रजिस्टर करती हैं. .bzl फ़ाइलों में कॉन्सटेंट, नियमों, मैक्रो, और फ़ंक्शन की परिभाषाएं दी जाती हैं.

नेटिव फ़ंक्शन और नेटिव नियम, BUILD फ़ाइलों में ग्लोबल सिंबल होते हैं. bzl फ़ाइलों को native मॉड्यूल का इस्तेमाल करके लोड करना होता है.

BUILD फ़ाइलों में सिंटैक्टिक से जुड़ी दो पाबंदियां हैं: 1) फ़ंक्शन को एलान करना मान्य नहीं है और 2) *args और **kwargs आर्ग्युमेंट की अनुमति नहीं है.

Python की तुलना में अंतर

  • ग्लोबल वैरिएबल में बदलाव नहीं किया जा सकता.

  • टॉप-लेवल पर for स्टेटमेंट इस्तेमाल करने की अनुमति नहीं है. इसके बजाय, उन्हें फ़ंक्शन में इस्तेमाल करें. BUILD फ़ाइलों में लिस्ट कंप्रीहेंशन का इस्तेमाल किया जा सकता है.

  • टॉप-लेवल पर if स्टेटमेंट इस्तेमाल करने की अनुमति नहीं है. हालांकि, if एक्सप्रेशन का इस्तेमाल किया जा सकता है: first = data[0] if len(data) > 0 else None.

  • डिक्शनरी में एक के बाद एक आइटम को ऐक्सेस करने के लिए, डिटरमिनिस्टिक क्रम.

  • रिकर्शन की अनुमति नहीं है.

  • इंट टाइप, 32-बिट के साइन वाले इंटिजर तक सीमित होता है. ओवरफ़्लो होने पर गड़बड़ी का मैसेज मिलेगा.

  • इटरेशन के दौरान किसी कलेक्शन में बदलाव करना एक गड़बड़ी है.

  • बराबर होने की जांच को छोड़कर, तुलना करने वाले ऑपरेटर <, <=, >=, > वगैरह को वैल्यू टाइप के हिसाब से तय नहीं किया जाता. कम शब्दों में: 5 < 'foo' से गड़बड़ी देगा और 5 == "5" से 'गलत' रिटर्न करेगा.

  • टपल में, आखिर में मौजूद कॉमा सिर्फ़ तब मान्य होता है, जब टपल को कोष्ठक के अंदर लिखा गया हो. इसका मतलब है कि 1, के बजाय (1,) लिखा जाना चाहिए.

  • डिक्शनरी लिटरल में डुप्लीकेट कुंजियां नहीं हो सकतीं. उदाहरण के लिए, यह एक गड़बड़ी है: {"a": 4, "b": 7, "a": 1}.

  • स्ट्रिंग को डबल-कोटेशन मार्क के साथ दिखाया जाता है. जैसे, repr को कॉल करते समय.

  • स्ट्रिंग को इटरेट नहीं जा सकता.

Python की ये सुविधाएं काम नहीं करतीं:

  • स्ट्रिंग इंप्लिसिट तरीके से जोड़ना. इसके बजाय, एक्सप्लिसिट + ऑपरेटर का इस्तेमाल करें.
  • तुलनाओं को एक साथ जोड़ना (जैसे कि 1 < x < 5).
  • class (struct फ़ंक्शन देखें).
  • import (load स्टेटमेंट देखें).
  • while, yield.
  • फ़्लोट और सेट टाइप.
  • जनरेटर और जनरेटर एक्सप्रेशन.
  • is (इसके बजाय, == का इस्तेमाल करें).
  • try, raise, except, finally (गंभीर गड़बड़ियों के लिए, fail देखें).
  • global, nonlocal.
  • ज़्यादातर बिल्ट-इन फ़ंक्शन, ज़्यादातर तरीके.