En esta página, se proporciona una descripción general de Starlark, antes conocido como Skylark, el lenguaje que se usa en Bazel. Para obtener una lista completa de las funciones y los tipos, consulta la referencia de la API de Bazel.
Para obtener más información sobre el lenguaje, consulta el repositorio de GitHub de Starlark.
Para obtener la especificación oficial de la sintaxis y el comportamiento de Starlark, consulta la Especificación del lenguaje Starlark.
Sintaxis
La sintaxis de Starlark se inspira en Python3. Esta es una sintaxis válida en 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)
La semántica de Starlark puede diferir de la de Python, pero las diferencias de comportamiento son poco frecuentes, excepto en los casos en que Starlark genera un error. Se admiten los siguientes tipos de Python:
Mutabilidad
Starlark favorece la inmutabilidad. Hay dos estructuras de datos mutables disponibles: listas y dicts. Los cambios en las estructuras de datos mutables, como agregar un valor a una lista o borrar una entrada en un diccionario, solo son válidos para los objetos creados en el contexto actual. Una vez que finaliza un contexto, sus valores se vuelven inmutables.
Esto se debe a que las compilaciones de Bazel usan la ejecución en paralelo. Durante una compilación, cada archivo .bzl
y cada archivo BUILD
obtienen su propio contexto de ejecución. Cada regla también se analiza en su propio contexto.
Veamos un ejemplo con el archivo 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 crea var
cuando se carga foo.bzl
. Por lo tanto, var
es parte del contexto de foo.bzl
. Cuando se ejecuta fct()
, lo hace dentro del contexto de foo.bzl
. Después de que se completa la evaluación de foo.bzl
, el entorno contiene una entrada inmutable, var
, con el valor [5]
.
Cuando otro bar.bzl
carga símbolos de foo.bzl
, los valores cargados permanecen immutables. Por este motivo, el siguiente código en bar.bzl
es ilegal:
# `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
Las variables globales definidas en los archivos bzl
no se pueden cambiar fuera del archivo bzl
que las definió. Al igual que en el ejemplo anterior con archivos bzl
, los valores que devuelven las reglas son inmutables.
Diferencias entre los archivos BUILD y .bzl
Los archivos BUILD
registran objetivos mediante llamadas a reglas. Los archivos .bzl
proporcionan definiciones para constantes, reglas, macros y funciones.
Las funciones nativas y las reglas nativas son símbolos globales en los archivos BUILD
. Los archivos bzl
deben cargarlos con el módulo native
.
Hay dos restricciones sintácticas en los archivos BUILD
: 1) declarar funciones es ilegal y 2) no se permiten los argumentos *args
y **kwargs
.
Diferencias con Python
Las variables globales son inmutables.
No se permiten las sentencias
for
en el nivel superior. En su lugar, úsalas dentro de las funciones. En los archivosBUILD
, puedes usar comprensiones de listas.No se permiten las sentencias
if
en el nivel superior. Sin embargo, se pueden usar expresionesif
:first = data[0] if len(data) > 0 else None
.Es el orden determinista para iterar a través de diccionarios.
No se permite la recursividad.
El tipo int se limita a números enteros de 32 bits con firma. Los desbordamientos arrojarán un error.
Modificar una colección durante la iteración es un error.
Excepto por las pruebas de igualdad, los operadores de comparación
<
,<=
,>=
,>
, etc. no se definen en todos los tipos de valores. En resumen:5 < 'foo'
arrojará un error y5 == "5"
mostrará un valor falso.En las tuplas, una coma final solo es válida cuando la tupla está entre paréntesis, es decir, cuando escribes
(1,)
en lugar de1,
.Los literales de diccionario no pueden tener claves duplicadas. Por ejemplo, este es un error:
{"a": 4, "b": 7, "a": 1}
.Las cadenas se representan con comillas dobles (como cuando llamas a repr).
Las cadenas no son iterables.
Las siguientes funciones de Python no son compatibles:
- concatenación de cadenas implícita (usa el operador
+
explícito) - Comparaciones encadenadas (como
1 < x < 5
) class
(consulta la funciónstruct
).import
(consulta la sentenciaload
).while
,yield
.- tipos de números de punto flotante y conjuntos.
- generadores y expresiones de generadores.
is
(en su lugar, usa==
).try
,raise
,except
,finally
(consultafail
para ver los errores fatales).global
,nonlocal
.- la mayoría de las funciones integradas y la mayoría de los métodos.