Parsing Tree-sitter
Parsing Tree-sitter
Seção intitulada “Parsing Tree-sitter”Parse código fonte em arvores de sintaxe concretas usando Tree-sitter. Baseado nos bindings go-tree-sitter.
Tree-sitter produz arvores de sintaxe que:
- Representam a estrutura completa do código fonte
- Atualizam incrementalmente conforme o código muda
- Sao robustas a erros de sintaxe (parsing parcial)
- Suportam queries baseadas em padroes usando S-expressions
Carregamento
Seção intitulada “Carregamento”local treesitter = require("treesitter")Linguagens Suportadas
Seção intitulada “Linguagens Suportadas”| Linguagem | Aliases | No Raiz |
|---|---|---|
| Go | go, golang | source_file |
| JavaScript | js, javascript | program |
| TypeScript | ts, typescript | program |
| TSX | tsx | program |
| Python | python, py | module |
| Lua | lua | chunk |
| PHP | php | program |
| C# | csharp, cs, c# | compilation_unit |
| HTML | html, html5 | document |
| Markdown | markdown, md | document |
| SQL | sql | - |
local langs = treesitter.supported_languages()-- {go = true, javascript = true, python = true, ...}Quick Start
Seção intitulada “Quick Start”Parse de Código
Seção intitulada “Parse de Código”local code = [[func hello() { return "Hello!"}]]
local tree, err = treesitter.parse("go", code)if err then return nil, errend
local root = tree:root_node()print(root:kind()) -- "source_file"print(root:child_count()) -- numero de declaracoes top-levelQuery na Arvore de Sintaxe
Seção intitulada “Query na Arvore de Sintaxe”local code = [[func hello() {}func world() {}]]
local tree = treesitter.parse("go", code)local root = tree:root_node()
-- Encontrar todos os nomes de funçãolocal query = treesitter.query("go", [[ (function_declaration name: (identifier) @func_name)]])
local captures = query:captures(root, code)for _, capture in ipairs(captures) do print(capture.name, capture.text)end-- "func_name" "hello"-- "func_name" "world"Parsing
Seção intitulada “Parsing”Parse Simples
Seção intitulada “Parse Simples”Parse de código fonte em uma arvore de sintaxe. Cria um parser temporario internamente.
local tree, err = treesitter.parse("go", code)| Parâmetro | Tipo | Descrição |
|---|---|---|
language | string | Nome ou alias da linguagem |
code | string | Código fonte |
Retorna: Tree, error
Parser Reutilizavel
Seção intitulada “Parser Reutilizavel”Criar um parser para parsing repetido ou atualizacoes incrementais.
local parser = treesitter.parser()parser:set_language("go")
local tree1 = parser:parse("package main")
-- Parse incremental com arvore antigalocal tree2 = parser:parse("package main\nfunc foo() {}", tree1)
parser:close()Retorna: Parser
Métodos do Parser
Seção intitulada “Métodos do Parser”| Método | Descrição |
|---|---|
set_language(lang) | Definir linguagem do parser, retorna boolean, error |
get_language() | Obter nome da linguagem atual |
parse(code, old_tree?) | Parse de código, opcionalmente com arvore antiga para parsing incremental |
set_timeout(duration) | Definir timeout de parse (string como "1s" ou nanossegundos) |
set_ranges(ranges) | Definir ranges de bytes para parse |
reset() | Resetar estado do parser |
close() | Liberar recursos do parser |
Arvores de Sintaxe
Seção intitulada “Arvores de Sintaxe”Obter No Raiz
Seção intitulada “Obter No Raiz”local tree = treesitter.parse("go", "package main")local root = tree:root_node()
print(root:kind()) -- "source_file"print(root:text()) -- "package main"Métodos da Tree
Seção intitulada “Métodos da Tree”| Método | Descrição |
|---|---|
root_node() | Obter no raiz da arvore |
root_node_with_offset(bytes, point) | Obter raiz com offset aplicado |
language() | Obter objeto de linguagem da arvore |
copy() | Criar copia profunda da arvore |
walk() | Criar cursor para travessia |
edit(edit_table) | Aplicar edicao incremental |
changed_ranges(other_tree) | Obter ranges que mudaram |
included_ranges() | Obter ranges incluidos durante parsing |
dot_graph() | Obter representação em grafo DOT |
close() | Liberar recursos da arvore |
Edicao Incremental
Seção intitulada “Edicao Incremental”Atualizar a arvore quando o código fonte muda:
local code = "func main() { x := 1 }"local tree = treesitter.parse("go", code)
-- Marcar edicao: mudou "1" para "100" no byte 19tree:edit({ start_byte = 19, old_end_byte = 20, new_end_byte = 22, start_row = 0, start_column = 19, old_end_row = 0, old_end_column = 20, new_end_row = 0, new_end_column = 22})
-- Re-parse com arvore editada (mais rapido que parse completo)local parser = treesitter.parser()parser:set_language("go")local new_tree = parser:parse("func main() { x := 100 }", tree)Nos representam elementos na arvore de sintaxe.
Tipos de No
Seção intitulada “Tipos de No”local node = root:child(0)
-- Informação de tipoprint(node:kind()) -- "package_clause"print(node:type()) -- igual a kind()print(node:is_named()) -- true para nos significativosprint(node:grammar_name()) -- nome da regra gramaticalNavegação
Seção intitulada “Navegação”-- Filhoslocal child = node:child(0) -- por indice (base 0)local named = node:named_child(0) -- apenas filhos nomeadoslocal count = node:child_count()local named_count = node:named_child_count()
-- Irmaoslocal next = node:next_sibling()local prev = node:prev_sibling()local next_named = node:next_named_sibling()local prev_named = node:prev_named_sibling()
-- Pailocal parent = node:parent()
-- Por nome de campolocal name_node = func_decl:child_by_field_name("name")local field = node:field_name_for_child(0)Informação de Posicao
Seção intitulada “Informação de Posicao”-- Offsets em byteslocal start = node:start_byte()local end_ = node:end_byte()
-- Posicoes linha/coluna (base 0)local start_pt = node:start_point() -- {row = 0, column = 0}local end_pt = node:end_point() -- {row = 0, column = 12}
-- Texto fontelocal text = node:text()Deteccao de Erro
Seção intitulada “Deteccao de Erro”if root:has_error() then -- Arvore contem erros de sintaxeend
if node:is_error() then -- Este no especifico e um erroend
if node:is_missing() then -- Parser inseriu este no para recuperar de erroendS-Expression
Seção intitulada “S-Expression”local sexp = node:to_sexp()-- "(source_file (package_clause (package_identifier)))"Queries
Seção intitulada “Queries”Pattern matching usando a linguagem de query do Tree-sitter (S-expressions).
Criar Query
Seção intitulada “Criar Query”local query, err = treesitter.query("go", [[ (function_declaration name: (identifier) @func_name parameters: (parameter_list) @params )]])| Parâmetro | Tipo | Descrição |
|---|---|---|
language | string | Nome da linguagem |
pattern | string | Padrão de query em sintaxe S-expression |
Retorna: Query, error
Executar Query
Seção intitulada “Executar Query”-- Obter todas as capturas (achatadas)local captures = query:captures(root, source_code)for _, capture in ipairs(captures) do print(capture.name) -- "@func_name" print(capture.text) -- texto real print(capture.index) -- indice da captura -- capture.node e o objeto Nodeend
-- Obter matches (agrupados por padrão)local matches = query:matches(root, source_code)for _, match in ipairs(matches) do print(match.id, match.pattern) for _, capture in ipairs(match.captures) do print(capture.name, capture.node:text()) endendControle de Query
Seção intitulada “Controle de Query”-- Limitar escopo da queryquery:set_byte_range(0, 1000)query:set_point_range({row = 0, column = 0}, {row = 10, column = 0})
-- Limitar matchesquery:set_match_limit(100)if query:did_exceed_match_limit() then -- Existem mais matchesend
-- Timeout (string de duração ou nanossegundos)query:set_timeout("500ms")query:set_timeout(1000000000) -- 1 segundo em nanossegundos
-- Desabilitar padroes/capturasquery:disable_pattern(0)query:disable_capture("func_name")Inspecao de Query
Seção intitulada “Inspecao de Query”local pattern_count = query:pattern_count()local capture_count = query:capture_count()local name = query:capture_name_for_id(0)local id = query:capture_index_for_name("func_name")Cursor de Arvore
Seção intitulada “Cursor de Arvore”Travessia eficiente sem criar objetos de no a cada passo.
Travessia Basica
Seção intitulada “Travessia Basica”local cursor = tree:walk()
-- Comecar na raizprint(cursor:current_node():kind()) -- "source_file"print(cursor:current_depth()) -- 0
-- Navegarif cursor:goto_first_child() then print(cursor:current_node():kind()) print(cursor:current_depth()) -- 1end
if cursor:goto_next_sibling() then -- moveu para proximo irmaoend
cursor:goto_parent() -- voltar ao pai
cursor:close()Métodos do Cursor
Seção intitulada “Métodos do Cursor”| Método | Retorna | Descrição |
|---|---|---|
current_node() | Node | No na posicao do cursor |
current_depth() | integer | Profundidade (0 = raiz) |
current_field_name() | string? | Nome do campo se houver |
current_field_id() | integer | ID do campo (0 se nenhum) |
current_descendant_index() | integer | Indice de descendente do no atual |
goto_parent() | boolean | Mover para pai |
goto_first_child() | boolean | Mover para primeiro filho |
goto_last_child() | boolean | Mover para ultimo filho |
goto_next_sibling() | boolean | Mover para proximo irmao |
goto_previous_sibling() | boolean | Mover para irmao anterior |
goto_descendant(index) | - | Mover para descendente por indice |
goto_first_child_for_byte(n) | integer? | Mover para filho contendo byte |
goto_first_child_for_point(pt) | integer? | Mover para filho contendo ponto |
reset(node) | - | Resetar cursor para no |
reset_to(cursor) | - | Resetar cursor para posicao de outro cursor |
copy() | Cursor | Criar copia do cursor |
close() | - | Liberar recursos |
Metadados de Linguagem
Seção intitulada “Metadados de Linguagem”local lang = treesitter.language("go")
print(lang:version()) -- versão ABIprint(lang:node_kind_count()) -- numero de tipos de noprint(lang:field_count()) -- numero de camposprint(lang:parse_state_count()) -- numero de estados de parse
-- Lookup de tipo de nolocal kind = lang:node_kind_for_id(1)local id = lang:id_for_node_kind("identifier", true)local is_named = lang:node_kind_is_named(1)
-- Lookup de campolocal field_name = lang:field_name_for_id(1)local field_id = lang:field_id_for_name("name")| Condição | Tipo | Retentável |
|---|---|---|
| Linguagem não suportada | errors.INVALID | não |
| Linguagem sem binding | errors.INVALID | não |
| Padrão de query inválido | errors.INVALID | não |
| Posicoes invalidas | errors.INVALID | não |
| Parse falhou | errors.INTERNAL | não |
Veja Error Handling para trabalhar com erros.
Referência de Sintaxe de Query
Seção intitulada “Referência de Sintaxe de Query”Queries Tree-sitter usam padroes S-expression:
; Match um tipo de no(identifier)
; Match com nomes de campo(function_declaration name: (identifier))
; Captura com @nome(function_declaration name: (identifier) @func_name)
; Multiplos padroes[ (function_declaration) (method_declaration)] @declaration
; Wildcards(_) ; qualquer no(identifier)+ ; um ou mais(identifier)* ; zero ou mais(identifier)? ; opcional
; Predicados((identifier) @var (#match? @var "^_")) ; regex matchVeja Tree-sitter Query Syntax para documentação completa.