Lua é uma linguagem de programação usada nos módulos da Wikipédia através da extensão Scribunto. Esta página pretende apresentar a linguagem de uma forma resumida, para uma compreensão mais completa sobre a linguagem veja o manual de referencia Lua da extensão.

Nos módulos a linguagem é praticamente igual ao Lua versão 5.1, removidas algumas funções que não fazem sentido dentro da Wikipédia e adicionadas algumas que ajudam a trabalhar com a estrutura do código-wiki. Então tutoriais sobre a linguagem Lua em geral também são úteis no aprendizado da linguagens, veja por exemplo a a documentação oficial da linguagem em português e o tutorial de lua-users.org.

Para usar um módulo em uma página da Wikipédia ele precisa retornar uma tabela com funções, essas funções podem então ser invocadas com a sintaxe {{#invoke:nome do módulo|função do módulo|argumentos passados para o frame}}. Os argumentos passados para o frame são como os argumentos de uma predefinição, só que em vez de estarem disponíveis nos formatos {{{1}}}, {{{2}}} ou {{{alguma palavra}}} estão disponíveis em frame.args, que é uma tabela Lua {['1']='valor equivalente a {{{1}}}', ['2']='valor equivalente a {{{2}}}'}.

Estruturas básicas

editar

Diferentemente do que acontece nas predefinições, onde todos os dados são tratado como texto ou números, em Lua existe tipos diferentes de estruturas de dados, e elas são armazenadas em variáveis. Os principais tipos de estruturas de dados usadas em Lua são: nil, true, false, números, strings (texto), funções e tabelas. Elas podem ser declaradas da seguinte forma:

nulo = nil
verdadeiro = true
falso = false
-- isto é um comentário, tudo que for escrito após -- é ignorado pelo código
numero = 123  -- os nomes das variáveis não podem conter acentos
texto = 'isto é uma string, ou texto'
funcao = function(n)
    local resposta = (n + numero) * 2 -- uma variável local só é acessível dentro do trecho em que foi declarada
    return 'o valor de (' .. n .. ' + ' .. numero .. ') × 2 é ' .. resposta
end -- funções devem ser terminadas com end
x = funcao(8)  -- o valor da varaável x será 'o valor de (8 + 123) × 2 é 262'
tabela = {'este é o valor 1', 'este é o valor 2', x = 'este é o valor x', ['y'] = 'este é o valor y',
  ['número'] = 2,  -- quando declarado neste formato a chave de um valor da tabela pode conter acento
  ['tabela'] = {'tabela', 'dentro', 'da', 'tabela'},
  ['número 123'] = numero,  -- adicionando um valor que está em outra variável
  ['função'] = funcao  -- nesse caso o valor é uma função
}

nil, true, false e operadores lógicos

editar

nil é um valor especial que indica a ausência de valor, ao tentar obter o valor de uma variável que não existe o valor retornado será nil, e quando uma variável local é declarada sem um valor específico, seu valor inicial será nil.

true e false são usados quando uma variável só admite dois valores, verdadeiro ou falso. É um valor geralmente retornado por operações de comparação como x > 5 ou y ~= ''.

Em algumas operações as expressões são transformadas em valores true ou false para serem processadas. Esse é o caso dos operadores and e or e das declarações if e while. Mas é preciso ter atenção porque diferentemente de outras linguagens de programação, 0 (zero), '' (string vazia) e {} (tabela vazia) são considerados true.

O and e or são operadores lógicos. Considerando duas expressões e1 e e2, e1 and e2 retorna e1 se e1 for falso e retorna e2 se e1 for verdadeiro, e1 or e2 retorna e1 se e1 verdadeiro e e2 se e1 for falso. Isso é útil quando se deseja testar várias condições ou retornar valores diferentes de acordo com alguma condição sem usar o if, veja alguns exemplos:

a = 32 and 76  -- a = 76
b = 28 and false  -- b = false
c = 0 or nil or 2  -- c = 0, pois 0 é considerado true
d = a and b or c and 4  -- d = 76 and false or 0 and 4, então d = 4

Operações com números

editar

Os operadores aritméticos que podem ser usados com números são +, -, * (vezes), / (dividido), ^ (potência) e % (resto da divisão). Esses operadores só funcionam com números, porém se uma string com números for usada com esses operadores a string será transformada em número, então '2' + '3' é igual a 5.

Além dos operadores acima existem também as funções da biblioteca math.

Principais funções da biblioteca math
math.abs (x) retorna o valor absoluto de x, ou seja, transforma em positivo se for negativo
math.ceil (x) retorna o menor inteiro maior ou igual a x, em outras palavras, arredonda para cima
math.floor (x) retorna o maior inteiro menor ou igual a x, em outras palavras, arredonda para baixo
math.fmod (x, y) retorna o resto da divisão de x por y, é o mesmo que x % y
math.log (x) retorna o logaritmo natural de x
math.log10 (x) retorna o logaritmo de x na base 10, outras bases podem ser obtidas com divisão, pois logba = log a / log b
math.max (x, ···) retorna o valor máximo entre os seus argumentos
math.min (x, ···) retorna o valor mínimo entre os seus argumentos
math.modf (x) retorna dois números, a parte integral de x e a parte fracionária de x
math.pi retorna valor de pi
math.pow (x, y) retorna xy, é o mesmo que usar x^y
math.sqrt (x) retorna a raiz quadrada de x, é o mesmo que x^0.5

tabela completa em mw:Extension:Scribunto/Lua reference manual/pt-br#Math library

Veja alguns exemplos de usos de operações com números:

a = (2 * 8)^4  -- a = 16^4 = 65536
b = math.floor(math.sqrt(a) / 3)  -- b = math.floor(256 / 3) = math.floor(85.333333333333) = 85
c = math.max(a, b, 2, 10, math.abs(-1000))  -- c = math.max(65536, 85, 2, 10, 1000) = 65536

Operações com strings

editar

A principal operação de string é a concatenação, ou seja, juntar strings, para isso se utiliza .. (dois pontos-finais), 'duas' .. ' ' .. 'palavras' se transforma em 'duas palavras'. Ao se utilizar .. com números eles são forçados a se tornarem strings, 'x = ' .. 3 se transforma em 'x = 3'. Para forçar um número a se tornar uma string também pode-se utilizar a função tostring(num).

A biblioteca string e mw.ustring são usadas para fazer operações com strings, as duas bibliotecas têm as mesmas funçãoes, a diferença é que a string considera caracteres unicode formados por mais de um byte (como as letras com acento) como sendo dois caracteres, o que pode gerar erros no processamentos de palavras que têm esses caracteres, já a mw.ustring considera todos caracteres como um caractere, por isso ele é mais usada. Abaixo estão as funções mais usadas da mw.ustring, que funcionarão de forma identica com a string em textos que contenham apenas caracteres de 1 byte (caracteres ASCII).

mw.ustring.find(s, pattern[, init[, plain]])

Procura pattern na string s, se encontrar retorna a posição onde a correspondência começa e a posição onde termina, se não encontrar retorna nil. O terceiro argumento init é opcional e diz a posição em s onde começar a busca, o padrão é 1. O pattern é um Lua pattern (explicado mais abaixo) a menos que o quarto argumento plain (opcional) seja true, se for true pattern é considerado uma busca simples, sem considerar nenhum caractere como caractere "mágico" de Lua pattern, note que se plain for fornecido init também deve ser.

mw.ustring.format (formatstring, ···)

Retorna formatstring formatado com os argumentos que seguem da mesma forma que a função printf da linguagem C. Em resumo, todo %s em formatstring é trocado por um argumento, e se precisar que um argumento numérico seja mostrado como número inteiro use %d, com casas decimais use %f, com um número exato de casas decimais use %.1f para uma casa decimal, %.2f para duas, etc. E alguns outros padrões comumente usados são: %x e %X para número hexadecimal em caixa baixa e alta, %e e %E para notação científica e %02d para forçar dois algarismos em números (1 a 9 é exibido 01 a 09).

mw.ustring.gmatch (s, pattern)

Retorna uma função iteradora, geralmente usada no laço for, que irá retornar a próxima captura de pattern em s sempre que chamada, quando não houver mais capturas a função irá retornar nil. Se pattern tiver grupos, irá retornar os grupos da captura. Esta função costuma ser usada junto com o for.

mw.ustring.gsub (s, pattern, repl [, n])

Retorna s com as correspondências de pattern substituídas por repl, se n for fornecido só realiza as primeiras n substituições.

mw.ustring.len (s)

Retorna o comprimento da string s.

mw.ustring.lower (s)

Retorna s com todas letras convertidas para minúscula.

mw.ustring.match (s, pattern [, init])

Procura pattern na string s, se encontrar retorna a correspondência ou, se pattern tiver grupos, retorna os grupos. Se init for informado a busca é iniciada na posição init.

mw.ustring.rep (s, n)

Retorna a string s repetida n vezes.

mw.ustring.sub (s, i [, j])

Retorna um pedaço (uma substring) de s, da posição i até j, se j não for fornecido será até o fim de s. A posição pode ser negativa indicando contagem a partir do fim da string, -1 significa o último caractere.

mw.ustring.upper (s)

Retorna s com todas letras convertidas para maiúscula.

Patterns

editar

Lua patterns são similares às expressões regulares, mas com algumas diferenças:

  • Não tem o "|" (ou).
  • Não tem o "{x,y}" (quantificador finito).
  • Não tem o "\b" (limítrofe de palavra).
  • Não tem "(?...)" (grupos especiais).
  • O "?" (opcional) não funciona em grupos, apenas em caracteres.
  • O "." (ponto) captura todos caracteres, incluindo a quebra de linha.
  • O caractere de escape e de grupos mágicos é "%", e não "\".
  • O "-" é equivalente ao "*?" (repete o caractere o mínimo possível), e "+?" é escrito por exemplo como "aa-" ("a+?" em regex).

Operações com tabelas

editar

Todo item de uma tabela tem sua chave que é única dentro da tabela, por exemplo em {['x']='a', ['y']='b'} um item tem chave 'x' e valor 'a' e outro tem chave 'y' e valor 'b'. Quando uma tabela é criada indicando somente os valores, uma chave numérica será automaticamente criada para cada item começando em 1, então em {'a', 'b'} um item tem a chave 1 e valor 'a' e o outro chave 2 e valor 'b', essa é uma tabela em que todas chaves são numéricas. Note que as chaves da tabela frame.args nunca são numéricas, os parâmetros numéricos são colocados dentro de strings ('1', '2', '3', etc). Todas funções abaixo, com exceção da pairs, são usadas para fazer operações apenas nos itens com chaves numéricas.

table.concat (t [, sep [, i [, j]]])

Concatena (junta) os itens de uma tabela com chaves numéricas formando uma string. Se fornecido sep é colocado entre os itens. As posições i e j se fornecido são o primeiro e último item a concatenar.

table.insert (t, [pos,] value)

Insere o valor value na tabela t na posição (chave) pos, se pos não for fornecido o valor será inserido na primeira posição vaga, que geralmente é o fim da tabela. Se a chave pos já tiver um valor, então esse valor e todos valores seguintes serão deslocados para dar espaço.

table.maxn (t)

Retorna a máxima posição (chave) numérica da tabela t.

table.remove (t [, pos])

Remove o item da posição pos da tabela t, e se houver um item na posição seguinte esse e todos os itens que seguem serão "puxados" para preencher o espaço.

table.sort (t [, comp])

Ordena os valores da tabela t. Uma função comp pode ser fornecida para computar a ordem, a função deve receber dois argumentos e retornar true quando o primeiro for menor.

ipairs (t)

Função para ser usada no laço for para iterar as chaves numéricas da uma tabela t começando pela chave 1.

pairs (t)

Função para ser usada no laço for para iterar todos os itens de uma tabela, numéricos ou não. Os itens iterados não seguem uma ordem específica. Durante a iteração é seguro modificar o valor ou remover itens da tabela, porém a adição de novas chaves pode trazer resultados inesperados.

Outras funções

editar

Variáveis globais e locais

editar

Toda variável que não for declarada como local é uma variável global, variáveis globais são acessíveis em qualquer parte do código, e é inclusive acessível pelas funções dos módulos carregados dentro do módulo principal, e da mesma forma as variáveis globais desses módulos ficam acessíveis dentro do módulo principal. Por isso é importante manter como global somente variáveis que precisam ser acessadas em outras partes do código.

A forma mais utilizada de utilizar variáveis globais é criar uma tabela para cada módulo e colocar todas as funções desse módulo que devem estar acessíveis em qualquer parte do código dentro dessa tabela, dessa forma evita-se que uma variável seja confundida com outra variável de mesmo nome em outra parte do código ou em outro módulo que tenha sido importado.

Variáveis locais são declaradas com a palavra local antes do nome da variável, variáveis locais não precisam ter um valor inicial, quando um valor inicial não for declarado o valor inicial é nil. Uma variável local só é mantida dentro do trecho em que foi declarada, se for declarada no início de uma função ela é mantida até o fim da função, se for declarada dentro de um if ela é mantida até o fim do if, o mesmo vale para else, for e outras estruturas de controle. Se uma variável for declarada local fora de uma função, ela é acessível dentro daquele módulo, outros módulos que forem carregados ou um módulo que carregar esse módulo não podem acessá-la.

Estruturas de controle

editar

Um bloco if serve para executar um código somente quando uma condição é verdadeira. Após um if pode vir um elseif, que testa uma outra condição se a anterior não for verdadeira e por fim pode ter um else, que executa um código se nenhuma das condições anteriores for verdadeira. Veja exemplos do uso dessas estruturas:

f = function(x)
    if type(x) == 'number' then
        return 'o argumento passado é um número'
    elseif type(x) == 'string' then
        return 'o argumento passado é uma string'
    else
        return 'o argumento passado não um número nem uma string'
    end
end

O laço for faz com que um código seja repetido várias vezes. Existem duas formas de se usar o for, a mais simples é a progressão artitimética, por exemplo for i = 1, 10 do vai executar o que estiver dentro do bloco 10 vezes, na primeira vez a variável i será 1, na segunda será 2 e assim por diante, veja o exemplo a seguir.

t = {}
for i = 1, 4 do
    table.insert(t, i * 2)
end
lista = table.concat(t, ', ')  -- lista = '2, 4, 6, 8'

A outra forma de usar o for é atravez de funções iteradoras no formato for x in f() do, em que f é uma função iteradora. As principais funções iteradoras são pairs e ipairs. A função pairs é usada dentro do for no formato for k, v in pairs(t) do onde t é uma tabela. O código dentro do for será executado uma vez para cada item, em cada vez a variável k será a chave do item e v o seu valor. Como as tabelas não gravam a ordem em que os itens foram inseridos nela, as vezes é necessário usar a função 'ipairs. A ipairs funciona com a mesma sintaxe da pairs, mas itera somente os itens com chave numérica, começando pelo item 1 e continuando pelo 2, 3, 4, etc até que o próximo número não exista. Se por exemplo a tabela tiver os itens 'a', 1, 2, 3 e 5, a pairs vai iterar todos, sem uma ordem específica, já a ipairs ira iterar somente os itens 1, 2 e 3, nessa ordem, não passa pelo 'a' pois não é uma chave numérica e não passa pelo 5 pois não existe o 4. Veja o exemplo:

tabela = {[1]='banana', [2]='maçã', ['3']='mamão', [5]='abacate', ['X']='morango'}
itens_pairs = {}
itens_ipairs = {}
for chave, valor in pairs(tabela) do
    table.insert(itens_pairs, chave .. ': ' .. valor)
end
for chave, valor in ipairs(tabela) do
    table.insert(itens_ipairs, chave .. ': ' .. valor)
end
lista1 = table.concat(itens_pairs, ', ')  -- lista1 = '2: maçã, 3: mamão, 1: banana, 5: abacate, X: morango'
lista2 = table.concat(itens_ipairs, ', ')  -- lista2 = '1: banana, 2: maçã'

while e repeat

editar

O laço while verifica uma condição e executa o código enquanto uma condição for verdadeira. Já o laço repeat...until faz o oposto, repete o código enquanto a condição não é verdadeira, e como a verificação é feita depois da execução do código o repeat vai sempre executar o código pelo menos uma vez.

t = {2, 6, 1, 8, 2, 9, 4, 7}
soma = 0
-- o while abaixo vai somar os números da tabela t enquanto a soma for menor que 10
while soma < 10 do
  soma = soma + table.remove(t, 1)
end
-- neste ponto soma é igual a 17 (2 + 6 + 1 + 8)
-- o repeat abaixo faz a mesma coisa, só que verifica a condição depois de executar o código
repeat
  soma = soma + table.remove(t, 1)
until soma >= 10
-- neste ponto soma é igual a 19 (17 + 2), pois o código foi executado antes de verificar a condição

Ver também

editar