Linguagem Starlark

Informar um problema Mostrar fonte Por noite · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

Esta página é uma visão geral do Starlark, antes conhecida como Skylark, a linguagem usada no Bazel. Para uma lista completa e tipos, consulte a Referência da API do Bazel.

Para saber mais sobre a linguagem, consulte o repositório do Starlark no GitHub (link em inglês).

Para a especificação oficial da sintaxe do Starlark e do usuário, consulte a Especificação de linguagem Starlark.

Sintaxe

A sintaxe do Starlark é inspirada no Python3. Esta é uma sintaxe válida no 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)

A semântica do Starlark pode ser diferente do Python, mas as diferenças comportamentais são raro, exceto nos casos em que Starlark gera um erro. O código Python a seguir têm suporte:

Mutabilidade

Starlark favorece a imutabilidade. Duas estruturas de dados mutáveis estão disponíveis: lists e dicts. Mudanças para elementos mutáveis estruturas de dados, como anexar um valor a uma lista ou excluir uma entrada em um dicionário são válidos apenas para objetos criados no contexto atual. Após um o contexto termina, os valores se tornam imutáveis.

Isso ocorre porque as versões do Bazel usam a execução paralela. Durante um build, cada .bzl e cada arquivo BUILD recebem o próprio contexto de execução. Cada regra também é analisados em seu próprio contexto.

Vejamos um exemplo com o arquivo 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

O Bazel cria var quando foo.bzl é carregado. var é, portanto, parte do pacote de foo.bzl contexto. Quando fct() é executado, isso ocorre no contexto de foo.bzl. Depois a avaliação de foo.bzl for concluída, o ambiente terá uma entrada imutável, var, com o valor [5].

Quando outra bar.bzl carrega símbolos de foo.bzl, os valores carregados permanecem imutáveis. Por esse motivo, o seguinte código em bar.bzl é 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

Variáveis globais definidas em arquivos bzl não podem ser alteradas fora da bzl que as definiu. Assim como o exemplo acima usando arquivos bzl, valores retornados pelas regras são imutáveis.

Diferenças entre arquivos BUILD e .bzl

Arquivos BUILD registram destinos fazendo chamadas para regras. .bzl arquivos fornecem definições de constantes, regras, macros e funções.

Funções nativas e regras nativas são símbolos globais em BUILD. Os arquivos bzl precisam carregá-los usando o módulo native.

Há duas restrições sintáticas em arquivos BUILD: 1) declarar funções ilegal e 2) os argumentos *args e **kwargs não são permitidos.

Diferenças com o Python

  • As variáveis globais são imutáveis.

  • Não são permitidas instruções for no nível superior. Use-os nas funções como alternativa. Em arquivos BUILD, você pode usar a compreensão de lista.

  • Não são permitidas instruções if no nível superior. No entanto, as expressões if pode ser usado: first = data[0] if len(data) > 0 else None.

  • Ordem determinística para iteração por dicionários.

  • A recursão não é permitida.

  • O tipo int é limitado a números inteiros assinados de 32 bits. Os estouros vão gerar um erro.

  • A modificação de uma coleção durante a iteração é um erro.

  • Exceto em testes de igualdade, os operadores de comparação <, <=, >=, > etc. são não definidos em nenhum tipo de valor. Resumindo: 5 < 'foo' vai gerar um erro e 5 == "5" vai retornar "falso".

  • Em tuplas, uma vírgula à direita só é válida quando a tupla está entre parênteses, quando você escreve (1,) em vez de 1,.

  • Literais de dicionário não podem ter chaves duplicadas. Por exemplo, este é um erro: {"a": 4, "b": 7, "a": 1}.

  • As strings são representadas com aspas duplas (como quando você chama repr).

  • Strings não são iteráveis.

Os seguintes recursos do Python não são compatíveis:

  • concatenação implícita de strings (use o operador + explícito).
  • Comparações encadeadas (como 1 < x < 5).
  • class (consulte a função struct).
  • import (consulte a instrução load).
  • while, yield.
  • de ponto flutuante e definido.
  • geradores e expressões geradoras.
  • is (use ==).
  • try, raise, except, finally (consulte fail para erros fatais).
  • global, nonlocal.
  • a maioria das funções embutidas, a maioria dos métodos.