Warning
Projeto experimental. APIs podem mudar sem aviso.
DSLX (ou Davi System: Lua XML) é um módulo que fornece ao Lua a capacidade de interpretar arquivos .dslx no qual permite ler código Lua e transformar o XML em Lua puro num mesmo arquivo e depois executa, parecido com o JSX.
A partir da versão 2.0 o módulo foi renomeado para dslx e reescrito sobre LPeg: o parser transforma o código em uma lista de nodes e o runtime gera (e executa) código Lua puro a partir deles.
graph TD;
A("código em DSLX") --> B("parser (LPeg)");
B --> C("lista de nodes");
C --> D("runtime: make_new_code");
D --> E("código Lua puro");
E --> F("executa");
luarocks install daviluaxmlRequisitos: Lua 5.5 e LPeg (instalado automaticamente como dependência).
No .dslx qualquer função definida no ambiente do Lua pode ser chamada no formato do XML. A tag vira uma chamada de função que recebe uma única tabela com o nome da tag, as props e os childrens:
--- codigo em dslx
local function soma(element)
local soma = 0
for _, valor in ipairs(element.childrens) do
soma = soma + valor
end
return soma + element.props.t
end
local pt = function(element) print(table.unpack(element.childrens)) end
<pt>
<soma t={9}>
{1}{2}{3}
</soma>
</pt>
print("final do test")--- vira codigo lua
local function soma(element)
local soma = 0
for _, valor in ipairs(element.childrens) do
soma = soma + valor
end
return soma + element.props.t
end
local pt = function(element) print(table.unpack(element.childrens)) end
pt{name="pt", props={}, childrens={soma{name="soma", props={t=9}, childrens={1, 2, 3}}}}
print("final do test")Props e childrens podem ser strings, expressões Lua, booleans ou elementos aninhados (conteúdo de um arquivo .dslx):
local function card(el)
-- props
el.props.titulo -- "olá" (string)
el.props.largura -- 10 (expressão Lua)
el.props.destaque -- true (boolean, só o nome da prop)
-- childrens
el.childrens[1] -- "texto " (texto literal)
el.childrens[2] -- 42 (expressão Lua)
el.childrens[3] -- tabela (elemento aninhado)
end
-- tag completa
local c1 = <card titulo="olá" largura={10} destaque>texto {40 + 2} <card/></card>
-- tag self-close
local c2 = <card titulo="tchau"/>
Um elemento aninhado vira uma chamada ao componente dentro da tabela de childrens: o valor retornado por ele é o que aparece em el.childrens. Se o componente retornar nil, o children simplesmente não existe. E como em Lua os valores são avaliados antes do constructor da tabela, o elemento aninhado roda antes do pai.
Quando seu projeto importa o módulo do DSLX ele carrega o loader do DSLX, sobrepondo o require no ambiente no qual foi importado, permitindo importar o .dslx da mesma forma do .lua:
package.path = package.path .. ";./dslx/test/?.dslx"
local dslx = require("dslx") -- instala o searcher automaticamente
local ok = require("1") -- carrega e executa 1.dslx
print("import ok:", ok) -- truelocal nodes = parser(code)Transforma o código em uma lista de nodes. Cada node tem um node_type: lua, script, string, children, props, element, full_element, element_self_close ou element_prop. Em falha, devolve uma tabela vazia.
runtime:addHandler(name, func)— registra um handler customizado pornode_type(namepode ser uma string ou uma tabela de nomes)runtime:expr(node, handlers)— devolve o código Lua de um noderuntime:make_new_code(nodes, handlers)— devolve o código Lua completoruntime:runtime(nodes, handlers)— compila e executa o código
compile({
input = "arquivo.dslx", -- arquivo .dslx de entrada (ou código, com asfile = false)
asfile = true, -- lê input como arquivo
tofile = true, -- escreve a saída em arquivo (false: devolve o código)
run = false, -- executa o resultado
output_name = nil, -- nome do arquivo de saída (default: nome do input)
output_ext = ".lua", -- extensão da saída
output_dir = ".", -- diretório da saída
relative_actual_file = false, -- resolve caminhos relativos ao arquivo que chamou
})Com tofile = false e run = false o compile devolve o código gerado; com run = true executa o resultado.
import.install()/import.uninstall()— adiciona/remove o searcher de .dslx dorequire()import.loadfile(filename, opts)— carrega um .dslx diretoimport.reload(name)— recarrega um módulo já importadoimport.clear()— limpa os módulos .dslx carregados e o cacheimport.path— opackage.pathusado pelo searcherimport.use_cache— cache de compilação (default: true)
local ok, err, nparams = is_element(minha_funcao)Global instalada pelo require("dslx"). Valida se uma função serve como elemento DSLX: precisa ser uma função que recebe exatamente 1 argumento (a tabela do elemento).
Retorna true se serve; senão false, a mensagem de erro e o número de parâmetros da função.
-
não é html, html é uma linguagem web para criação de páginas, o DSLX é um Lua+XML. e XML é uma linguagem de estruturação rígida para sistemas.
-
não é um substituto do Lua, o DSLX é para funcionar em conjunto ao Lua
Esse módulo é MIT. Sinta-se livre para brincar e fazer o que quiser a sua fork desse projeto, mantendo os créditos :)