関連記事
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
Goメモ-597 (Tree-sitterメモ-01)(下準備, Goバインディングのインストール) - いろいろ備忘録日記
Goメモ-598 (Tree-sitterメモ-02)(パーサーの生成と言語の設定) - いろいろ備忘録日記
Goメモ-599 (Tree-sitterメモ-03)(解析処理の実行とツリーの取得) - いろいろ備忘録日記
Goメモ-600 (Tree-sitterメモ-04)(シンタックスエラーの出力) - いろいろ備忘録日記
Goメモ-605 (Tree-sitterメモ-05)(ノードタイプ) - いろいろ備忘録日記
Goメモ-606 (Tree-sitterメモ-06)(ノードテキスト) - いろいろ備忘録日記
Goメモ-607 (Tree-sitterメモ-07)(ノードのトラバース(1), ループとコールバックで実施) - いろいろ備忘録日記
概要
以下、自分用のメモです。前回までのメモは関連記事にかかれている ブログ記事まとめ よりどうぞ。
今回は、前回に引き続きノードのトラバースについて。
tree_sitterには TreeCursor というオブジェクトが存在します。
このオブジェクトは Tree.Walk や Node.Walk から得られます。
このオブジェクトを利用すると配下のノードを再帰的にトラバースすることが可能なのですが、若干利用方法が難しいです。
本サンプルでは、TreeCursorを用いたノードのトラバースを行っています。
サンプル
main.go
package main import ( "errors" "fmt" "log" "strings" tree_sitter "github.com/tree-sitter/go-tree-sitter" tree_sitter_c "github.com/tree-sitter/tree-sitter-c/bindings/go" ) const ( C_CODE = `#include <stdio.h> #include <stdlib.h> int add(int x, int y) { // ADD return x+y; } int main(void) { int z = add(1, 2); if (z < 10) { printf("%d\n", z); } for (int i = 0; i < z; i++) { switch (i) { case 0: printf("first\n"); return; default: printf("other\n"); return; } } return EXIT_SUCCESS; } ` ) func main() { log.SetFlags(0) if err := run(); err != nil { log.Fatal(err) } } func run() error { var ( p = tree_sitter.NewParser() l = tree_sitter.NewLanguage(tree_sitter_c.Language()) err error ) defer p.Close() if err = p.SetLanguage(l); err != nil { return err } var ( tree = p.Parse([]byte(C_CODE), nil) ) if tree == nil { return errors.New("構文解析に失敗: Parse()") } defer tree.Close() var ( root = tree.RootNode() cursor = root.Walk() callback = func(node *tree_sitter.Node, depth uint32) { var ( k = node.Kind() d = int(depth) * 2 ) fmt.Printf("%s%-25s\n", strings.Repeat(" ", d), k) } ) defer cursor.Close() // *TreeCursorは閉じる必要がある walk(cursor, callback) return nil } // walk は、TreeCursorを利用して指定したノード配下をトラバースする関数です。 func walk(cursor *tree_sitter.TreeCursor, callback func(*tree_sitter.Node, uint32)) { var ( node = cursor.Node() // 現在のノード depth = cursor.Depth() // 現在の深さ ) // *TreeCursorでは、Namedだけではなく全てのノードが回るのでNamedだけ対象にするには絞り込む必要がある if node.IsNamed() { callback(node, depth) } // 子ノードが存在する場合は移動 if cursor.GotoFirstChild() { for { walk(cursor, callback) // 兄弟ノードが存在すれば移動 if !cursor.GotoNextSibling() { break } } // 親ノードに戻る cursor.GotoParent() } }
実行結果
$ task task: [default] go run . translation_unit preproc_include system_lib_string preproc_include system_lib_string function_definition primitive_type function_declarator identifier parameter_list parameter_declaration primitive_type identifier parameter_declaration primitive_type identifier compound_statement comment return_statement binary_expression identifier identifier function_definition primitive_type function_declarator identifier parameter_list parameter_declaration primitive_type compound_statement declaration primitive_type init_declarator identifier call_expression identifier argument_list number_literal number_literal if_statement parenthesized_expression binary_expression identifier number_literal compound_statement expression_statement call_expression identifier argument_list string_literal string_content escape_sequence identifier for_statement declaration primitive_type init_declarator identifier number_literal binary_expression identifier identifier update_expression identifier compound_statement switch_statement parenthesized_expression identifier compound_statement case_statement number_literal expression_statement call_expression identifier argument_list string_literal string_content escape_sequence return_statement case_statement expression_statement call_expression identifier argument_list string_literal string_content escape_sequence return_statement return_statement identifier
参考情報
Goのおすすめ書籍
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。