Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ecosystem on parse.y

Avatar for S.H. S.H.
February 28, 2026
210

Ecosystem on parse.y

福岡Rubyist会議05

Avatar for S.H.

S.H.

February 28, 2026

Transcript

  1. C拡張での実装 VALUE integer_node_new(const NODE *node) { VALUE result = rb_class_new_instance(0,

    0, rb_cIntegerNode); // CRubyのASTが持つ値をインスタンス変数へ詰める rb_ivar_set(result, rb_intern("@val"), rb_node_integer_literal_val(node)); rb_ivar_set(result, rb_intern("@minus"), RNODE_INTEGER(node)->minus == TRUE ? Qtrue : Qfalse); rb_ivar_set(result, rb_intern("@base"), INT2FIX(RNODE_INTEGER(node)->base)); return result; }
  2. KanayagoのLSPの強み PrismとRuby LSPでもできるが、エッジケー スはすり抜ける Kanayagoでは除外できる a rescue b => c

    in d # PrismではSyntaxErrorにならない # parse.yではSyntaxErrorになる # [Bug #21713] # https://bugs.ruby-lang.org/issues/21713
  3. LSPサーバを実装 def analyze(source) diagnostics = [] # KanayagoでソースコードをASTへ変換 result =

    Kanayago.parse(source) # SyntaxErrorの場合はエラー情報を詰める if result.invalid? error = result.error diagnostic = create_diagnostic(error, result.script_lines) diagnostics << diagnostic end diagnostics end
  4. 出力例(Minitestの場合) # frozen_string_literal: true require "test_helper" class UserTest < Minitest::Test

    def test_initialize # Arguments: # - name (required) # - age (required) skip "Not implemented yet" end def test_adult? # Comparisons: >= (@age >= 18) # Boundary value suggestions: # @age >= 18: [17 (below), 18 (boundary), 19 (above)] skip "Not implemented yet" end end
  5. 修正したコード例 VALUE vparser = TypedData_Make_Struct(0, struct ruby_parser, &ruby_parser_data_type, parser); /*

    ... */ VALUE vast = rb_parser_compile_string(vparser, "main", source, 0); rb_ast_t *ast = rb_ruby_ast_data_get(vast); VALUE ast_node = ast_to_node_instance(ast->body.root); // vast、vparserがGCされるとSegmentation faultになる // GCされないようにガードを付けている RB_GC_GUARD(vast); RB_GC_GUARD(vparser);