Skip to content

Tags pass: evaluate #eq?/#any-of?/#not-any-of? so keyword tables move out of C++ #355

Open

Description

@joyful-ii-V-I

Part of the language-architecture cleanup tracked in #354 ("common stays common").

Problem. The tags pass never evaluates tree-sitter query predicates (see the notes in queries/javascript/tags.scm and queries/cpp/tags.scm). So any language whose definitions are a call with a keyword head (Elixir def/defmodule, Clojure defn in #349, Ruby DSLs) has to keep its keyword list in C++. That is most of why src/ingest_elixir.h exists, and there are two near-identical copies of the idea already (elixirFunctionKeyword/elixirMetadataAttribute in ingest_elixir.h and macroBodyKeyword in ingest_relations.h, 0.82–0.96 similar by ripwire --clones).

Change. Evaluate the string predicates #eq?, #any-of? and #not-any-of? in the tags pass, reusing the predicate loop that src/ingest_astquery.h already has. No #match? regex in the tags pass (the performance note at ingest_astquery.h explains why). Then move one keyword table (Elixir's is the natural first) into its tags.scm.

Acceptance.

  • A gate, written red first, with a tiny fixture per predicate.
  • Every existing language's output is byte-identical (existing goldens + a before/after map on the test fixtures).
  • kParserVer + kIngestParserVerMirror bumped together to the number a maintainer reserves for you (ask in the PR).

Size: 1–2 days. Maintainers plan to start this on 2026-09-30 unless someone claims it first; comment here to claim it.

Activity

  1. joyful-ii-V-I commented on Oct 4, 2026

    @joyful-ii-V-I
    CollaboratorAuthor

    Adding to this from the #373 review (Ruby method lookup): its framework name tables (RSpec expectation and matcher targets, FactoryBot builders, Rails callback / if:/unless: / rescue_from … with: declarations, the send/try/method(:m) family, delegation) are written as C++ in the Ruby path. They are good candidates for the same move as the Elixir/Clojure keyword tables here: string predicates in tags.scm, so the next language's framework tables are data too. Not blocking #373, which followed the current architecture.

  2. conka8 commented on Oct 21, 2026

    @conka8

    I'd like to pick this up. I'd make the tags pass evaluate the string predicates #eq?, #any-of? and #not-any-of? by reusing the predicate loop in src/ingest_astquery.h (no #match?), with the gate written red first and a tiny fixture per predicate, then move Elixir's keyword table from src/ingest_elixir.h into its tags.scm and confirm every existing language's output stays byte-identical against the goldens. Could you assign it to me?

  3. joyful-ii-V-I commented on Oct 22, 2026

    @joyful-ii-V-I
    CollaboratorAuthor

    @conka8, welcome, and thank you! That plan is exactly the shape we hoped for: string predicates only, gate red first, one tiny fixture per predicate, Elixir first, and byte-identical goldens for every other language. Yes, please take it. I'm assigning it to you.

    One coordination note: @tag-und-nacht claimed slice 5a in #389 (same predicates, then Clojure's tables) and mentioned being busy for a while. Here's a split that keeps everyone's work: you land the shared evaluator plus Elixir's table here, and Clojure's defining-head and special-form tables stay with #389, ready to drop onto your evaluator. @tag-und-nacht, if you already have work in progress on the evaluator, say so here and we'll merge efforts. Nobody should redo anyone's work.

    A few hints that should save you time:

    • Where the loop lives: passesPredicates in src/ingest_astquery.h (around line 231) already walks the predicate steps per match. Read its step-group loop and buildPredicateRegexTable just above it together: the comment there says the two must agree on which steps they consume. A tags-pass evaluator that shares that loop (string predicates only) avoids a third copy. Keep #match? out of the tags pass; the WHY comment at the top of that file explains the regex cost that was measured.
    • What moves: elixirFunctionKeyword and elixirMetadataAttribute in src/ingest_elixir.h become #any-of? / #eq? lists in queries/elixir/tags.scm. The C++ call site that uses the first one is in src/ingest_sidecap.h (~line 2370); it should end up reading the capture instead. macroBodyKeyword in src/ingest_relations.h is the near-twin (0.82–0.96 similar by ripwire --clones). Note it in the PR, but don't feel you have to fold it in too.
    • Gates that will speak up: test/langidentitycheck.sh (a ratchet on Lang:: compares; moving the table out of C++ should LOWER it, which is the win to show), the per-language golden / byte-identity checks you mentioned, and test/gateexitcheck.sh + test/binoverridecheck.sh for the new gate itself (a new gate must fail when RIPWIRE_BIN points at a failing stub).
    • Tooling: ripwire . --callers=passesPredicates and ripwire . --edit-check=elixirFunctionKeyword show every reader before you move anything. CONTRIBUTING's "Adding a language: common stays common" section is the design note this issue comes from.

    Ask here any time if something looks odd. Small draft PRs early are very welcome.

  4. conka8 commented on Oct 22, 2026

    @conka8

    PR is up: #426 . It adds the shared evaluator (string predicates only, no #match? in the tags pass) and moves both Elixir tables, elixirFunctionKeyword and elixirMetadataAttribute, into queries/elixir/tags.scm. The new gate is red on main first. Byte identity is 1274/1274 SAME, with plug and phoenix added as real Elixir repos.

    One question is in the PR: which kParserVer number should I use? I put 216 as a placeholder.

    @tag-und-nacht, Clojure's tables can drop onto src/infra/tspredicates.h whenever you're ready. predicateStrings reads a list back from the compiled query for walks that run outside a match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requesthelp wantedExtra attention is needed

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions