Старларк Язык

Эта страница представляет собой обзор языка Starlark , ранее известного как Skylark, используемого в Bazel. Полный список функций и типов см. в справочнике по Bazel API .

Дополнительные сведения о языке см. в репозитории Starlark на GitHub .

Официальную спецификацию синтаксиса и поведения Starlark см. в Спецификации языка Starlark .

Синтаксис

Синтаксис 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:

Изменчивость

Старларк выступает за неизменность. Доступны две изменяемые структуры данных: списки и словари . Изменения в изменяемых структурах данных, такие как добавление значения в список или удаление записи в словаре, действительны только для объектов, созданных в текущем контексте. После завершения контекста его значения становятся неизменяемыми.

Это связано с тем, что сборки 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 создает var при foo.bzl . Таким образом, 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 .

  • Детерминированный порядок перебора словарей.

  • Рекурсия не допускается.

  • Тип Int ограничен 32-битными целыми числами со знаком. Переполнение вызовет ошибку.

  • Изменение коллекции во время итерации является ошибкой.

  • За исключением тестов на равенство, операторы сравнения < , <= , >= , > и т. д. не определены для типов значений. Вкратце: 5 < 'foo' выдаст ошибку, а 5 == "5" вернет false.

  • В кортежах замыкающая запятая действительна только тогда, когда кортеж находится между круглыми скобками — когда вы пишете (1,) вместо 1, .

  • Словарные литералы не могут иметь повторяющиеся ключи. Например, это ошибка: {"a": 4, "b": 7, "a": 1} .

  • Строки представлены двойными кавычками (например, при вызове repr ).

  • Строки не являются итерируемыми.

Следующие функции Python не поддерживаются:

  • неявная конкатенация строк (используйте явный оператор + ).
  • Цепные сравнения (например, 1 < x < 5 ).
  • class (см. функцию struct ).
  • import (см. оператор load ).
  • while , yield .
  • типы float и set.
  • генераторы и генераторные выражения.
  • is (вместо этого используйте == ).
  • try , raise , except , finally (см. fail для фатальных ошибок).
  • global , nonlocal .
  • большинство встроенных функций, большинство методов.