Skip to content

feat(dsl-v2): フロントエンド + check(lex + rpn + parse + 型検査)を実装#108

Open
redpeacock78 wants to merge 96 commits into
dsl-v2from
task/2026-07-02-dsl-v2-front
Open

feat(dsl-v2): フロントエンド + check(lex + rpn + parse + 型検査)を実装#108
redpeacock78 wants to merge 96 commits into
dsl-v2from
task/2026-07-02-dsl-v2-front

Conversation

@redpeacock78

@redpeacock78 redpeacock78 commented Jul 2, 2026

Copy link
Copy Markdown
Owner

概要

DSL v2 コンパイラのフロントエンド 3 ステージ(Task 1–6 / 13)。行ベース正規表現による現行の desugar 方式を、段階型コンパイラ(lex → RPN IR → 再帰下降 + スタック還元 AST)へ移行する第一弾。

構成

  • dsl/v2/main.awk — BEGIN-only ドライバ(V2_DUMP=<stage> で各段の TSV ダンプ)
  • dsl/v2/util.awk — 診断 v2_diag(line,col,msg)(stderr へ <file>:<line>:<col>: error: <msg>V2_ERRORS 集計)
  • dsl/v2/lex.awk — 行分類とトークナイズ(TOK テーブル、DSL 行の原文保存)
  • dsl/v2/rpn.awk — 操車場法による式の RPN 変換 + 文構造マーカー(FUNC_OPEN/LET/LETQ/WHEN/OF/ARM_OPEN/ARM_CLOSE/WHEN_END/RETURN/STMT_END/RAWLINE)。解釈不能行は RAWLINE で素通し
  • dsl/v2/parse.awk — 式のスタック還元 + 文の再帰下降で flat-array AST(AST テーブル)を構築。when パターン(ok v / ng e<Type> / _)、PARAM/TYPEANN、パニックモード回復

テスト

tests/dsl2/run.sh — fixture 22 件 PASS(lex/rpn/ast 各段の TSV 期待値照合 + stderr エラー fixture 4 件)

レビュー

各 Task ごとに実装レビュー済み(spec 準拠 + 品質、修正ループ込みで全件 Approved)。check(型推論)・emit は後続 PR。

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 新機能
    • DSL v2 のコンパイルフロー(字句解析→RPN/AST→静的検査→出力)を追加し、when ... of/end、関数/演算子優先順位、型注釈・型付きパターン、文字列補間、正規表現リテラルに対応。
    • V2_DUMP で各工程の結果(lex/rpn/ast/types)を確認可能。
  • バグ修正
    • 文字列/コメント/補間/正規表現周りの誤判定を抑え、診断(未終了ブロック、型不一致、網羅性、パイプ/HTML整合など)を強化。
  • テスト
    • ゴールデン/エラー期待値とテスト実行スクリプトを拡充。

redpeacock78 and others added 14 commits July 2, 2026 11:17
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
…es, BEGIN-only driver)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- dsl/v2/lex.awk を新規作成: v2_is_dsl(), v2_lex(), v2_tok_line(),
  v2_tok_str()(補間 #{} 対応), v2_tok_word(), v2_push(), v2_ident_kind()
- main.awk: 仮 v2_lex スタブを削除し @include "dsl/v2/lex.awk" に置換
- tests/dsl2/lex_let_typed, lex_when_block, lex_interp: golden fixture 追加

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
stray `end` が DSL 検出行に現れた場合 in_when が -1 になり、
後続ブロック追跡が壊れる問題を修正。in_block と同様にデクリメント後
に `if (in_when < 0) in_when = 0` ガードを追加。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- v2_rpn(): = 右辺・return 後続を式区間として検出し、それ以外は OPERAND 素通し
- v2_shunt_expr(): 演算子優先度テーブル (|> 10 L … . 100 L) に従い RPN 出力
- v2_pop_ge() で右結合 (?? ^) を正しく処理
- 関数呼び出し: FN: プッシュ方式で arity を追跡 (COMMA でインクリメント)
- v2_find_expr_end(): RBRACE・文開始 KW でネスト深さ 0 の式末尾を判定
- テスト: rpn_arith_prec (1+2*3→1 2 3 * +), rpn_pipe_coalesce (|>/??優先度),
  rpn_call_arity (g(x,y+1)→arity=2)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
a ?? b ?? c → a b c ?? ??(右結合)を検証。
v2_pop_ge の条件 (tp > prec || (tp==prec && assoc=="L")) により
同優先度 R 結合演算子はスタックから弾かれず正しく処理される。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v2_tok_str の文字列終端処理で `if (length(acc) > 0)` ガードが
空文字列 `""` の STR トークン発行を抑制していた。
ガードを除去し、常に v2_push("STR", ...) を呼ぶよう修正。

- dsl/v2/lex.awk: length ガードを削除
- tests/dsl2/rpn_when_marker/input.awk: return "" を復元
- tests/dsl2/rpn_when_marker/expected.rpn.tsv: empty val 列を更新
- tests/dsl2/rpn_let_marker/input.awk: let z = "" を追加
- tests/dsl2/rpn_let_marker/expected.rpn.tsv: 4 エントリ追加

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v2_rpn_stmt に v2_is_rawline() ヘルパーを追加。
LBRACE/LBRACK/RBRACK/COLON/ARROW/INTERP_* を含む行は
式文として解釈せず、RAWLINE マーカー + 原文テキスト OPERAND
を発行して行末まで消費する。

- dsl/v2/lex.awk: V2_LINE_TEXT[lineno] に生行テキストを保存
- dsl/v2/rpn.awk: v2_is_rawline() 追加、v2_rpn_stmt を更新
- tests/dsl2/rpn_rawline/: 新規フィクスチャ(a[i] = 1)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

DSL v2 の字句解析、RPN 生成、AST 構築、静的検査、実行ドライバ、テスト実行スクリプトが追加され、補間、正規表現、when、pipe、型エイリアス、添字代入、ブランド型の処理が接続されています。

Changes

DSL v2 コンパイラ実装

Layer / File(s) Summary
実行ドライバと診断
dsl/v2/util.awk, dsl/v2/main.awk, tests/dsl2/run.sh, tests/dsl2/passthrough_plain_awk/*
診断出力、工程実行、ダンプ、emit 制御、テスト実行スクリプト、透過 AWK 出力を追加。
字句解析
dsl/v2/lex.awk, tests/dsl2/lex_*/*
DSL 判定、文字列・正規表現・補間のトークン化、未注釈関数の DSL 強制判定、lex 系 fixture を追加。
RPN 生成
dsl/v2/rpn.awk, tests/dsl2/rpn_*/*
式還元、function/let/when/return/type/index 代入の RPN 化と関連 fixture を追加。
AST 構築
dsl/v2/parse.awk, tests/dsl2/ast_*/*
RPN を消費して式、文、パターン、when、func、let、return の AST ノードを構築する。
静的検査
dsl/v2/check.awk, tests/dsl2/check_*/*, tests/dsl2/err_*/*
組込みシグネチャ、型推論、when 網羅性、補間、pipe、ブランド型、alias 循環の検査を追加。

Estimated code review effort: 5 (Critical) | ~120 minutes

Poem

ぴょこんと拾った 文字のかけら
くるくる回して RPN にし
枝をのばして AST を編み
耳でしっかり エラーを聞いて
v2 の森が ぴかりと光る 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed DSL v2 のフロントエンド、lex/RPN/parse、型検査の実装を的確に要約しており、変更内容と一致しています。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@redpeacock78

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bee2a5e4ef

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk
Comment thread dsl/v2/rpn.awk
Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk
Comment thread dsl/v2/lex.awk Outdated
Comment thread dsl/v2/lex.awk Outdated
Comment thread dsl/v2/rpn.awk
Comment thread dsl/v2/rpn.awk Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dsl/v2/lex.awk`:
- Around line 26-44: The block-depth tracking in v2_lex is counting raw line
text, so braces inside strings or comments can corrupt in_block state and stop
parsing too early. Update the {}/depth accounting to operate on tokens produced
by v2_tok_line (or the lexer’s token stream) rather than gsub on line text, and
keep the when/end tracking in v2_lex aligned with that token-based block state.
- Around line 101-164: v2_tok_str currently treats unterminated strings and
#{...} interpolations as fully consumed, which lets invalid DSL slip through
without diagnostics. Update v2_tok_str in dsl/v2/lex.awk to detect when the scan
ends before finding a closing " or INTERP_CLOSE, and emit an error token or
fatal diagnostic instead of returning normal consumption. Make sure the
string/interpolation handling around v2_push, v2_tok_word, and the final return
path preserves the location from startcol/lineno for accurate reporting.

In `@dsl/v2/main.awk`:
- Around line 21-30: The current main flow in v2_emit() always exits
successfully even though emit is still a stub, so change the
v2_check()/v2_emit() path in main.awk to avoid silent success when DSL tokens
are present. Either make the regular execution path report a diagnostic and fail
whenever unresolved DSL input would be emitted, or restrict this entry point to
dump-only behavior via V2_DUMP; keep the decision logic near the existing
v2_check, v2_dump_types, and v2_emit symbols so the unfinished emit
implementation cannot return exit 0 on normal DSL input.

In `@dsl/v2/parse.awk`:
- Around line 122-131: The close-marker loop in v2_p_block is stopping on val
alone, so non-MARKER entries like OPERANDs that share the same text can
prematurely end the block. Update the close condition to require both the
expected close_marker value and a matching kind check before breaking, and keep
the existing v2_stmt_dispatch flow unchanged so only real markers terminate the
block.

In `@dsl/v2/rpn.awk`:
- Around line 431-437: 裸の式文が parse 側で AST から消えてしまうため、v2_shunt_expr
の結果をそのまま還元するのではなく、式文用の文マーカーを出すようにしてください。rpn.awk の v2_shunt_expr と、その親の parse 側で
MARKER 文しか追加しない処理を見直し、EXPR のような文マーカーと STMT_END を導入して裸の式文を親ノードに残すように対応してください。
- Around line 183-210: `v2_find_expr_end()`
は改行をまたいで式を伸ばしすぎているため、行境界で走査を止めるようにしてください。`TOK[k,"kind"]` と `TOK[k,"text"]`
を見ているこの関数内で、同一行のみを RHS として扱う条件を追加し、`let`/`function`/`when`/`end`
の境界判定に加えて次行の裸式やアクセス式を吸収しないように修正してください。AST 生成と還元スタックに影響するため、`v2_find_expr_end()`
の終端判定を行ベースに制限してください。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a663a869-c429-4227-a1a7-5ae83ad72435

📥 Commits

Reviewing files that changed from the base of the PR and between 78dae77 and bee2a5e.

⛔ Files ignored due to path filters (19)
  • tests/dsl2/ast_arith/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_call/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_func_params/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_letq/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_pat_typed/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_pipe_chain/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_strlit/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_when_nested/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/lex_interp/expected.lex.tsv is excluded by !**/*.tsv
  • tests/dsl2/lex_let_typed/expected.lex.tsv is excluded by !**/*.tsv
  • tests/dsl2/lex_when_block/expected.lex.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_arith_prec/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_call_arity/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_coalesce_right_assoc/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_func_marker/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_let_marker/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_pipe_coalesce/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_rawline/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_when_marker/expected.rpn.tsv is excluded by !**/*.tsv
📒 Files selected for processing (31)
  • dsl/v2/lex.awk
  • dsl/v2/main.awk
  • dsl/v2/parse.awk
  • dsl/v2/rpn.awk
  • dsl/v2/util.awk
  • tests/dsl2/ast_arith/input.awk
  • tests/dsl2/ast_call/input.awk
  • tests/dsl2/ast_func_params/input.awk
  • tests/dsl2/ast_letq/input.awk
  • tests/dsl2/ast_pat_typed/input.awk
  • tests/dsl2/ast_pipe_chain/input.awk
  • tests/dsl2/ast_strlit/input.awk
  • tests/dsl2/ast_when_nested/input.awk
  • tests/dsl2/err_op_underflow/expected_stderr
  • tests/dsl2/err_op_underflow/input.awk
  • tests/dsl2/err_unclosed_when/expected_stderr
  • tests/dsl2/err_unclosed_when/input.awk
  • tests/dsl2/lex_interp/input.awk
  • tests/dsl2/lex_let_typed/input.awk
  • tests/dsl2/lex_when_block/input.awk
  • tests/dsl2/passthrough_plain_awk/expected.awk
  • tests/dsl2/passthrough_plain_awk/input.awk
  • tests/dsl2/rpn_arith_prec/input.awk
  • tests/dsl2/rpn_call_arity/input.awk
  • tests/dsl2/rpn_coalesce_right_assoc/input.awk
  • tests/dsl2/rpn_func_marker/input.awk
  • tests/dsl2/rpn_let_marker/input.awk
  • tests/dsl2/rpn_pipe_coalesce/input.awk
  • tests/dsl2/rpn_rawline/input.awk
  • tests/dsl2/rpn_when_marker/input.awk
  • tests/dsl2/run.sh

Comment thread dsl/v2/lex.awk Outdated
Comment thread dsl/v2/lex.awk Outdated
Comment thread dsl/v2/main.awk Outdated
Comment thread dsl/v2/parse.awk
Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk
redpeacock78 and others added 6 commits July 2, 2026 21:17
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- v2_find_expr_end: 深さ0での return を終端に追加、depth0でのソース行変化も終端とする
- v2_rpn_let: Dict<Str, Str> / Str|Int のような複数トークンの型注釈を1つの OPERAND として読む
- v2_p_block: close_marker 比較に kind=="MARKER" を追加し、OPERAND の val 一致による誤クローズを防止
- tests/dsl2/run.sh: 診断エラーで exit 1 になる rpn/lex/ast/types ダンプ fixture でも
  set -e によりテスト全体が中断しないよう actual=$(...) を || true でガード

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- v2_shunt_expr: 空の [] / {} を OPERAND として受理
- v2_shunt_expr/v2_reduce_op: 式先頭・演算子直後・(直後・,直後の -/! を arity 1 の
  NEG/NOT として扱う(UNOP ノード)
- v2_is_arm_pat: KW "default" を正規の arm 開始として認識(default: / default name:)
- v2_shunt_expr: STR/INTERP_OPEN..INTERP_CLOSE の連続を 1 個の STRLIT オペランドに
  再構成し、AST 上は補間文字列全体が 1 ノードで載るようにする

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- rpn/parse: 裸の式文(例: hawk.app.get(...))を EXPR/STMT_END マーカーで囲み、
  parse 側で v2_parse_expr_stmt により AST に接続する(従来は式結果が
  どこにも addchild されず消えていた)
- parse: v2_parse_pat で `ng<AuthError>` のようにバインド変数のない型付き
  パターン(parts[1] 自体が tag<Type> になるケース)を PAT+TYPEANN に分離
- main: v2_emit は DSL トークンが存在する場合、コード生成未実装である旨を
  診断してエラー終了する(従来は passthrough のみで exit 0 の silent 成功だった)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v2_mark_unannotated_func(fix B)は v2_strip_str_comment の出力を gsub で
ブレース深さカウントに使っていたが、この関数は文字列内の補間開始 "#{" だけを
残し対応する閉じ "}" は取り除くため、出力が非対称になっていた。
無注釈関数本体に補間文字列(例: "a#{x}b")があると "{" だけが余分にカウントされ、
本体終端 "}" の探索がファイル末尾まで暴走し、後続の plain awk(BEGIN ブロック等)
まで丸ごと V2_FORCE_DSL[] に誤マークされ passthrough が壊れていた。

ブレース深さ計測専用に v2_strip_for_brace_count を追加し、文字列内容と補間を
(開き・閉じとも)対称に丸ごと除去するようにした。あわせて、本体終端が
見つからずファイル末尾まで depth が 0 に戻らなかった場合は、残り全行を
誤って DSL マークしないよう安全策を追加した。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@redpeacock78

Copy link
Copy Markdown
Owner Author

bot レビュー指摘 17 件、すべて docs/dsl.md(v1 仕様)と突合のうえ有効と判断し、以下のコミットで対応しました。

対応マッピング

分類 指摘 対応コミット
lex 文字列・コメント内キーワード誤反応 (A) 9667c1f
lex 注釈なし DSL 関数ヘッダ検出漏れ (B) 9667c1f + aad2da0
lex ブレース深さの raw gsub カウント (C) 9667c1f
lex 未終端文字列の silent 無視 (D) 9667c1f
rpn 式の行境界・return 終端 (E) cc1330d
rpn ネスト {} での FUNC 早期クローズ (F) E+G の副次効果で解消(回帰 fixture rpn_nested_brace 追加)
rpn 型注釈の複数トークン消費 union/generic (G) cc1330d
rpn [] / {} 空リテラル (H) c8d4a9b
rpn 単項 - / ! (I) c8d4a9b
rpn default arm (J) c8d4a9b
rpn 補間文字列を 1 オペランド化 (K) c8d4a9b
rpn+parse 裸の式文が AST から消える → EXPR マーカー (L) 32b9ff5
parse 型付き no-bind パターン ng <Type>: (M) 32b9ff5
parse v2_p_block close 判定に MARKER kind チェック (N) 32b9ff5
main emit スタブの silent exit 0 (O) 32b9ff5

内部レビューで A×B の相互作用(無注釈関数本体の補間文字列でブレース深さが過剰カウント → 後続の素の awk が誤って DSL 分類)を検出し、aad2da0 で対称ストリップ関数 v2_strip_for_brace_count を新設して修正済みです。

後続タスクへの繰り延べ

  • 非空 dict/list リテラルの RPN/AST 表現 → Task 10(emit 基礎)
  • #{} 内部式の AST 展開 → Task 11(emit 補間)。現段階では仕様どおり STRLIT (Str) として 1 オペランド扱い
  • emit 実体 → Task 10。それまでは V2_DUMP=lex|rpn|ast|types を案内するエラーで exit 1

テスト: tests/dsl2/run.sh 42 fixtures 全 green(各修正に TDD で fixture 追加)。

@redpeacock78

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aad2da040e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk
Comment thread dsl/v2/check.awk Outdated
Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/rpn.awk Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
dsl/v2/lex.awk (1)

214-239: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

補間内のネストした {}INTERP_CLOSE と誤認しないでください。

"#{foo({})}" のような補間式では Line 218 が最初の } を補間終端にしてしまい、LBRACE だけが残って文字列断片と in_block 深さが壊れます。補間内ではローカルの brace depth を持ち、depth 0 の } だけを INTERP_CLOSE にしてください。

修正案
-function v2_tok_str(rest, lineno, startcol,    i, ch, ch2, acc, acc_col, consumed, closed_interp) {
+function v2_tok_str(rest, lineno, startcol,    i, ch, ch2, acc, acc_col, consumed, closed_interp, interp_depth, interp_col) {
@@
       if (ch2 == "{") {
+        interp_col = startcol + i - 1
@@
         v2_push("INTERP_OPEN", "#{", lineno, startcol + i - 1)
         i += 2
@@
         closed_interp = 0
+        interp_depth = 0
         while (i <= length(rest)) {
           ch = substr(rest, i, 1)
+          if (ch == "{") {
+            v2_push("LBRACE", "{", lineno, startcol + i - 1)
+            interp_depth++
+            i++
+            continue
+          }
           # 補間終端
           if (ch == "}") {
+            if (interp_depth > 0) {
+              v2_push("RBRACE", "}", lineno, startcol + i - 1)
+              interp_depth--
+              i++
+              continue
+            }
             v2_push("INTERP_CLOSE", "}", lineno, startcol + i - 1)
@@
         if (!closed_interp) {
-          v2_diag(lineno, startcol, "unterminated interpolation")
+          v2_diag(lineno, interp_col, "unterminated interpolation")
           return length(rest)
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dsl/v2/lex.awk` around lines 214 - 239, The interpolation scanner in lex.awk
is treating the first } inside a nested expression as INTERP_CLOSE, which breaks
cases like #{foo({})}. Update the interpolation loop to track a local brace
depth while scanning rest, incrementing on { and only emitting INTERP_CLOSE when
depth returns to 0; keep nested braces as part of the inner token stream. Use
the existing interpolation handling block around closed_interp,
v2_push("INTERP_CLOSE", ...), and v2_tok_word to locate the fix.
🧹 Nitpick comments (2)
dsl/v2/check.awk (1)

128-151: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

関数の再定義を検知していません。

v2_collect は同名の FUNC ノードが複数存在しても SIG[name,...] を無条件に上書きするため、関数の重複定義がエラーにならず静かに後勝ちになります。ユーザーの入力ミス(同名関数の誤った再定義)を見逃す原因になり得ます。

修正案
 function v2_collect(id,    k, name, child, argn) {
   if (AST[id,"kind"] == "FUNC") {
     name = AST[id,"text"]
+    if ((name,"arity") in SIG) {
+      v2_diag(AST[id,"line"], 1, "function '" name "' is already defined")
+    }
     SIG[name,"arity"] = 0
     SIG[name,"ret"]   = "Unknown"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dsl/v2/check.awk` around lines 128 - 151, `v2_collect` is overwriting
`SIG[name,...]` for duplicate `FUNC` nodes instead of detecting a redefinition.
Before assigning arity, return type, or args in `v2_collect`, check whether the
same function name has already been collected and raise an error on a repeated
`FUNC` definition rather than silently replacing the previous signature; use the
existing `AST`/`SIG` tracking in `v2_collect` to locate the duplicate and report
it.
dsl/v2/main.awk (1)

13-27: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

通常実行でも各ステージ直後で打ち切ってください
v2_lex() で最初の診断が出ても v2_rpn() / v2_parse() / v2_check() が続き、壊れた入力から追加診断が積み上がる余地があります。DSL2 のエラー fixture は部分一致なので、この種の混入も見逃されます。通常実行時だけ各ステージ後に if (V2_ERRORS) exit 1 を入れるとよいです。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dsl/v2/main.awk` around lines 13 - 27, The BEGIN pipeline in v2/main.awk
keeps running later stages after an error is already recorded, which can add
extra diagnostics from broken input. Update the staged flow around v2_lex,
v2_rpn, v2_parse, and v2_check so that in normal execution it exits immediately
whenever V2_ERRORS becomes nonzero, while preserving the existing V2_DUMP
early-return behavior for lex/rpn/ast/types.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dsl/v2/lex.awk`:
- Around line 71-75: In v2_mark_unannotated_func, the header checks are mixing
raw and stripped line content, which can incorrectly treat a commented or
string-contained function header as unannotated and leave the body to be parsed
as top-level DSL. Update the function to perform the function/header,
arrow-signature, and trailing-brace checks consistently on the comment-stripped
line data used by the lexer helpers, so the logic around V2_RAWLINE, stripped
text, and the unannotated function detection stays aligned.

---

Outside diff comments:
In `@dsl/v2/lex.awk`:
- Around line 214-239: The interpolation scanner in lex.awk is treating the
first } inside a nested expression as INTERP_CLOSE, which breaks cases like
#{foo({})}. Update the interpolation loop to track a local brace depth while
scanning rest, incrementing on { and only emitting INTERP_CLOSE when depth
returns to 0; keep nested braces as part of the inner token stream. Use the
existing interpolation handling block around closed_interp,
v2_push("INTERP_CLOSE", ...), and v2_tok_word to locate the fix.

---

Nitpick comments:
In `@dsl/v2/check.awk`:
- Around line 128-151: `v2_collect` is overwriting `SIG[name,...]` for duplicate
`FUNC` nodes instead of detecting a redefinition. Before assigning arity, return
type, or args in `v2_collect`, check whether the same function name has already
been collected and raise an error on a repeated `FUNC` definition rather than
silently replacing the previous signature; use the existing `AST`/`SIG` tracking
in `v2_collect` to locate the duplicate and report it.

In `@dsl/v2/main.awk`:
- Around line 13-27: The BEGIN pipeline in v2/main.awk keeps running later
stages after an error is already recorded, which can add extra diagnostics from
broken input. Update the staged flow around v2_lex, v2_rpn, v2_parse, and
v2_check so that in normal execution it exits immediately whenever V2_ERRORS
becomes nonzero, while preserving the existing V2_DUMP early-return behavior for
lex/rpn/ast/types.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6fb4aa7f-f4ee-460f-b802-9df79cf78c46

📥 Commits

Reviewing files that changed from the base of the PR and between bee2a5e and aad2da0.

⛔ Files ignored due to path filters (16)
  • tests/dsl2/ast_expr_stmt/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_pat_typed_nobind/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_when_default/expected.ast.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_sig_forward_ref/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/lex_brace_in_string/expected.lex.tsv is excluded by !**/*.tsv
  • tests/dsl2/lex_func_interp_passthrough/expected.lex.tsv is excluded by !**/*.tsv
  • tests/dsl2/lex_func_unannotated/expected.lex.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_dict_empty/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_expr_line_bound/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_interp_operand/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_list_empty/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_nested_brace/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_two_assigns/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_type_generic/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_type_union/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_unary/expected.rpn.tsv is excluded by !**/*.tsv
📒 Files selected for processing (30)
  • dsl/v2/check.awk
  • dsl/v2/lex.awk
  • dsl/v2/main.awk
  • dsl/v2/parse.awk
  • dsl/v2/rpn.awk
  • tests/dsl2/ast_expr_stmt/input.awk
  • tests/dsl2/ast_pat_typed_nobind/input.awk
  • tests/dsl2/ast_when_default/input.awk
  • tests/dsl2/check_sig_forward_ref/input.awk
  • tests/dsl2/err_arity/expected_stderr
  • tests/dsl2/err_arity/input.awk
  • tests/dsl2/err_emit_unimplemented/expected_stderr
  • tests/dsl2/err_emit_unimplemented/input.awk
  • tests/dsl2/err_unterminated_str/expected_stderr
  • tests/dsl2/err_unterminated_str/input.awk
  • tests/dsl2/lex_brace_in_string/input.awk
  • tests/dsl2/lex_func_interp_passthrough/input.awk
  • tests/dsl2/lex_func_unannotated/input.awk
  • tests/dsl2/lex_kw_in_string/expected.awk
  • tests/dsl2/lex_kw_in_string/input.awk
  • tests/dsl2/rpn_dict_empty/input.awk
  • tests/dsl2/rpn_expr_line_bound/input.awk
  • tests/dsl2/rpn_interp_operand/input.awk
  • tests/dsl2/rpn_list_empty/input.awk
  • tests/dsl2/rpn_nested_brace/input.awk
  • tests/dsl2/rpn_two_assigns/input.awk
  • tests/dsl2/rpn_type_generic/input.awk
  • tests/dsl2/rpn_type_union/input.awk
  • tests/dsl2/rpn_unary/input.awk
  • tests/dsl2/run.sh
✅ Files skipped from review due to trivial changes (12)
  • tests/dsl2/err_unterminated_str/expected_stderr
  • tests/dsl2/rpn_list_empty/input.awk
  • tests/dsl2/err_arity/expected_stderr
  • tests/dsl2/lex_kw_in_string/expected.awk
  • tests/dsl2/lex_brace_in_string/input.awk
  • tests/dsl2/rpn_type_generic/input.awk
  • tests/dsl2/lex_func_unannotated/input.awk
  • tests/dsl2/ast_when_default/input.awk
  • tests/dsl2/ast_expr_stmt/input.awk
  • tests/dsl2/err_unterminated_str/input.awk
  • tests/dsl2/rpn_dict_empty/input.awk
  • tests/dsl2/lex_func_interp_passthrough/input.awk
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests/dsl2/run.sh
  • dsl/v2/parse.awk
  • dsl/v2/rpn.awk

Comment thread dsl/v2/lex.awk Outdated
redpeacock78 and others added 10 commits July 3, 2026 23:40
DC: v2_regex_start_hereの許可リストが `~ ( , =` のみで、return /let/ や
&& /when/ のようなregexがstripされずletword誤検出→未実装DSL扱いに
なっていた。直前が値を作らないトークン(演算子・キーワード・行頭等)
なら regex とする判定に一般化。
DG: NUM正規表現が小数点前の数字を必須とし、.5がDOT+NUMに分解されて
stack underflow していた。直前が値でない位置限定で先頭ドット形を
1つのNUMトークンとして読み、v2_operand_nodeのNUMLIT判定も対応させる。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
補間#{}内の実引数がネストしたCALLのとき、そのネストcall自体の
arity・引数型検査を走らせず宣言戻り型を返すだけだった。
v2_interp_atom_typeにlineパラメータを追加し、v2_infer_interp_expr_type
のCALL分岐と同じarity/引数型検査をネスト呼び出しにも適用する。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…検出を追加する(DU+DP+DV)

DU: 補間#{}内のcall認識パターンがname(...)形のみで、json.decode<Int>(body)
のようなgeneric callがUnknownに落ち、sealed Resultをunwrapなしで
補間できていた。v2_interp_match_call_head/v2_interp_scan_genericを追加し、
rpn.awkのf<T>(...) -> f_t("T",...)正規化と同じ規約でarity注入・T置換を行う。
DP: 補間内 lhs |> callee(args) でRHSの明示引数を数えても検査してもいな
かった。LHSを含めた実効arityで既存PIPE検査(V)と同じ規則を適用する。
DV: 裸IDENT・call・pipeのどれでもない補間式(丸括弧包み変数を含む)が
Unknownを返しUntrustedをすり抜けていた。式テキスト中にUntrustedな
変数参照が含まれるかを走査するv2_interp_text_has_untrusted_refを
フォールバックに追加し、wave 11の既知課題「(raw) |> f() / f((raw))」
も併せて解消した。

check_interp_generic_ok fixtureは追加していない: 現行SIGに登録された
generic組込み(json.decode_t, ctx.req.json_t)は戻り型が常にResult<T,...>
でsealedであり、v2はuser定義genericも未サポートのため、非sealedな
generic callを補間内で正常型付けする構成が作れない。詳細は報告書に記載。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
数値推論が小数点の有無しか見ておらず、1e-2 のような負指数リテラルが
Intに推論され let x: Int = 1e-2 が通っていた。v1実測(dsl/desugar_let.awk
:_ds_infer_type)ではInt/Float判定正規表現がどちらも指数部付きリテラル
にマッチせず推論結果が""のまま無検査で通るため、v1にInt/Float区別は
無い。真値が非整数になる場合(小数点あり、または指数が負)のみFloatに
統一する。1e3のような非負指数の整数値はCMの既存fixtureどおりInt
のまま維持する。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resultのエラーパラメータがunionへのエイリアスのとき、err_partの分割前
にエイリアス展開されず、type Errors = AuthError|NotFoundError +
Result<Str, Errors>でng e<AuthError>:のみのwhenがnmem==1になり
missing-arm診断が出ずNotFoundError分岐が漏れていた。v2_expand_alias
を通してから分割する。wave11 CZ(真に単一のエラー型でのnmem==1 skip)
とは別のケース。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
pipe入力型のエイリアス解決が全体文字列がエイリアス名のときしか働かず、
R|Str(R = Result<Str, ParseError>のエイリアス)のようなunionだと
全体文字列のResult</Option<prefix判定をすり抜け、sealed分岐を
?=/whenなしでpipeできていた。DK/DLと同じくv2_split_unionでmember
単位に分割してから各memberをv2_resolve_sealedで判定する。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
lexが大文字始まり識別子をTYPEトークンにするため、パラメータ位置の
大文字名(function handler(Raw: Untrusted<Str>))がv2_rpn_funcのIDENT
限定判定でパラメータとしてemitされず失われていた。v1実測
(bash libexec/hawk-check)では大文字パラメータ名は普通に通ることを
確認済み。

rpn.awkでTYPEトークンもパラメータ名位置ではIDENT同様に受理する
よう修正。ただしparse.awk側の戻り値型/パラメータ名判定が「大文字
始まりなら戻り値型」という単純ヒューリスティックのままだと、大文字
パラメータ名を今度は戻り値型と誤認してparamスロット自体を失う
(wave11 CV報告書が既知の限界として記録していた非対称性そのもの)。
直後に:TYPE注釈OPERANDが続く場合は戻り値型ではあり得ない(戻り値型
注釈が後続することはない)ため確実にパラメータと判定できる条件を
追加し、rpn側の修正と組み合わせて解消した。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
式文のRAWLINE判定(v2_is_rawline)が行内の[の存在だけで機械的に
RAWLINEへ落としており、hawk.app.get(routes[0], 123)のような
対応済みINDEX式(shunting yardは単純な一階層添字を既にサポート済み。
BE/U)を含むcall文まで素通しになり、引数検査がスキップされていた。

v2_line_has_unsupported_indexを追加し、直前が値でない[(配列リテラル
等)・ネストした[・行内で閉じない[のみRAWLINE対象とする。文頭の
name[...] =形(代入文)はv2_index_assign_eq/CB専用の判定対象で、
ここに来た時点でDSLVAR未登録=構造化不可が確定済みのため二重構造化
せずRAWLINEのまま維持する(既存rpn_rawline/ast_rawline_preserved
fixtureで確認)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…iew C1)

union member自体がUntrusted<...>への型エイリアス(type U = Untrusted<Str>)
だと、展開前の生テキストではprefixが一致せずDK/DL/DVのUntrusted伝播
防御を丸ごとバイパスできていた(type U = Untrusted<Str>; x: Str|U で
safe.html.raw(x "!")がexit 0・診断なしで通過)。DSが同種の問題を
v2_resolve_sealedで解決しているのと同じ基準に揃え、member判定前に
エイリアス展開するよう修正。ついでにCONCAT分岐のコメント誤記
(CK/DL→DK/DL)も修正(review M1)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DTは型注釈付きの大文字パラメータのみ救っており、function handler(Raw)
のような型注釈なし大文字パラメータは依然としてparse.awkの戻り値型
ヒューリスティック(大文字始まりなら戻り値型)に誤認識され、PARAM
ノード自体が消失していた。本体中のRawは未束縛のUnknown型になり、
以後の型検査(Untrusted検査含む)を無診断で全てすり抜ける。複数
パラメータの場合、誤認識時点でパラメータ走査ループがbreakするため
後続の全パラメータ(Untrusted<Str>注釈付きでも)が巻き添えで失われる
ことも確認した。

命名ヒューリスティックでは本質的に解決できない(型注釈もアローも
無い大文字始まりパラメータと戻り値型は文字列上区別できない)ため、
rpn.awk側で戻り値型OPERANDにのみ"->"を前置し、parse.awk側はその
prefixの有無のみで判定する構造的な方式に変更した。戻り値型はARROW
トークンを実際に検出したときにしか生成されないため、命名に依存せず
確実に判別できる。DE/DTで使っていた大文字/エイリアス名ヒューリス
ティックは不要になり除去した。

RPN dumpの戻り値型OPERANDテキストが"Str"から"->Str"に変わるため、
既存のrpn/ast dumpステージfixture13件のexpected.rpn.tsvを更新した
(ast/typesステージの出力は変化なし)。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@redpeacock78

Copy link
Copy Markdown
Owner Author

Bot レビュー第 12+13 波(DC-DV、20 件)対応完了

Codex bot の指摘 20 件(第 12 波 DC-DM の 11 件 + 第 13 波 DN-DV の 9 件、P1×7 + P2×13)のうち 19 件を修正、1 件は v1 実測に基づきスキップしました。加えてレビューアで検出した Critical 2 件を修正しています(e6edddb..cf4cdc5 の 15 コミット、fixture 146→174 件 green)。

第 12 波(DC-DM)

ID 指摘 対応
DC return /let/ 等 return 系演算子直後の regex リテラルが未 strip で DSL 誤判定 ce4fa4a(strip の許可リストを非値トークン一般に拡張)
DD when 対象のエイリアスが binder 型導出前に未展開 8f73e67(Effect strip 後にエイリアス展開してから腕 binder を型付け)
DE 小文字エイリアスの戻り値型注釈が偽パラメータ化 dd6732b(CV と同じくエイリアス表参照で TYPEANN 判定。後述の C2 で構造的判定に置換され、既知限界も解消)
DF intersection 内に隠れたエイリアス循環が未検出 1a1d342(循環検査で & 分割後に各要素を再帰)
DG .5 形式の leading-dot float が未トークン化 ce4fa4a(数値トークンに先頭ドット形を追加、Float 推論)
DH index key のエイリアスが未展開で List/Dict キー検査誤判定 6635006(キー注釈をエイリアス展開してから比較)
DI 数値演算がエイリアス未展開で Count + Int を拒否 6635006(演算オペランド型をエイリアス展開してから Int/Float 判定)
DJ 非数値への単項マイナスが Unknown 素通り スキップ: v1 実測(libexec/hawk-check)で戻り値式の型検査自体が存在せず無条件許容 → v1 互換維持(Task 12 互換ゲート後の厳格化候補に記録)
DK Str|Untrusted<Str> union の補間で Untrusted 未伝播 ef3495c(member 単位で Untrusted 判定するヘルパを追加)
DL 同 union の concat で Untrusted 未伝播 ef3495c(DK と同一ヘルパを concat 規則にも適用)
DM 補間の } 探索が入れ子文字列内の } で停止 ef3495c(文字列リテラルをスキップしながら brace を走査)

第 13 波(DN-DV)

ID 指摘 対応
DN 補間内のネスト call 引数が arity/brand 未検査 f627d3a(CN/DB の検査機構をネスト call に再帰適用)
DO 1e-2 等の指数リテラルが Int 誤推論 9744bf4(指数部付きは Float 推論。第 9 波 CM の既知残件の解消)
DP 補間内 pipe の RHS 明示引数が未検査 42541cf(RHS 引数を分割し実効 arity を V と同規則で検査)
DQ Result エラーエイリアスが coverage 検査前に未展開 fe71044(err_part 分割前にエイリアス展開)
DR [ を含む式文が一律 RAWLINE 化され DSL call 検査を素通り 1d829c6(INDEX 対応可能な形のみ構造化、それ以外は従来どおり RAWLINE の安全側)
DS pipe 入力 union の sealed member が未拒否 14f52fc(member 分割 + エイリアス展開後に BB と同文言で sealed 拒否)
DT 大文字注釈付きパラメータが TYPE 扱いで消失し Untrusted 迂回 64f39be(TYPE トークンをパラメータ位置で受容。後述の C2 で構造的判定に置換)
DU 補間内の generic call name<...>(...) が未認識 42541cf(generic 形を認識し AE の T 置換 + sealed 拒否を適用)
DV 未対応補間式が Unknown→Str 扱いで Untrusted 隠蔽 42541cf(式テキストが Untrusted 変数を参照する場合は Untrusted へフォールバック。第 11 波の既知残課題「丸括弧包みすり抜け」もこれで解消)

レビューア検出分の修正

  • C1 (df625b8): DK/DL/DV 共通ヘルパが union member 単位のエイリアス展開をしておらず、type U = Untrusted<Str>; x: Str|U の 1 段エイリアスで防御をバイパスできた → member 判定前に v2_resolve_sealed を通す形に修正(多段エイリアスも検証済み)。
  • C2 (cf4cdc5): DT の修正が型注釈なしの大文字パラメータ function handler(Raw) {...} を救えず、パラメータ消失で型検査を素通りした → 命名ヒューリスティック自体を廃止し、rpn 段で戻り値型 OPERAND にのみ -> を前置する構造的判定へ転換(DE/DT の旧ヒューリスティックを除去、複数パラメータ時の巻き添え消失も同時解消。RPN dump の表記変更に伴い既存 fixture 13 件の expected.rpn.tsv を更新、ast/types ステージは無変更)。

補足

  • DU の正常系 fixture(check_interp_generic_ok)は未追加です。現行 SIG の generic 組込み(json.decode_t / ctx.req.json_t)はいずれも sealed な Result<T, ...> を返し、v2 はユーザー定義 generic 非対応のため、OK 系の形が構成できません。非 sealed generic が将来追加された際の追跡候補として記録しています。
  • DE の既知限界(パラメータ名と小文字エイリアス名の衝突)は C2 の構造的判定への転換で解消しました。

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

@redpeacock78 承知しました。第12+13波レビュー指摘20件(DC-DV)の対応内容を確認しました。

  • DC/DG: return系直後のregexリテラル未strip、.5形式floatの未トークン化、いずれも妥当な字句解析の拡張です。
  • DD/DH/DI/DQ: エイリアス未展開による各種検査回避(when binder型、index key、数値演算、Result エラーカバレッジ)、展開タイミングを揃えて一貫して解消されています。
  • DF: intersection内のエイリアス循環検出、&分割後の再帰、確認しました。
  • DK/DL/DM: union補間/concatでのUntrusted未伝播、入れ子文字列内}探索の停止、member単位のヘルパ導入で解消。
  • DN/DP/DU/DV: 補間内のネストcall・pipe RHS・generic call・未対応式のUntrusted隠蔽、いずれもCN/DB/AEの既存機構を再利用した堅実な拡張です。DVで第11波の丸括弧包みすり抜けも解消されたとのこと、良い副次効果です。
  • DR: [を含む式文の一律RAWLINE化、INDEX対応可能な形のみ構造化し、それ以外は安全側のRAWLINE維持という判断、妥当です。
  • DS: pipe入力unionのsealed member未拒否、BBと同文言での拒否、確認しました。
  • DJ: v1実測(libexec/hawk-check)で戻り値式の型検査自体が存在せず無条件許容という判断に基づくスキップ、これまでの方針と一貫しています。

レビューア検出分(C1/C2)について

  • C1: DK/DL/DV共通ヘルパのunion member単位エイリアス展開漏れ、type U = Untrusted<Str>のような1段エイリアスでの防御バイパスを検出・修正いただいた点、良い深掘りです。
  • C2: DTの修正が型注釈なし大文字パラメータの巻き添え消失を救えなかった問題に対し、命名ヒューリスティックを廃止してrpn段の構造的判定(戻り値型OPERANDへの->前置)に転換した対応、根本解決として妥当です。DE/DTの旧ヒューリスティックを完全に置き換えた点も含め、既存fixture 13件のexpected.rpn.tsv更新は理解しました。

DUの正常系fixture未追加(現行SIGのgeneric組込みが全てsealedなResultを返すため構成不可)は将来のトラッキング対象として承知しました。

修正前worktreeでの再現確認プロセス、引き続き丁寧です。変更内容のレビューを実施します。

(=^・ω・^=)

(=^・ω・^=)


✏️ Learnings added
Learnt from: redpeacock78
URL: https://github.com/redpeacock78/H-awk/pull/108

Timestamp: 2026-07-03T17:54:25.714Z
Learning: In the redpeacock78/H-awk repository's DSL v2 implementation (dsl/v2/check.awk), as of PR `#108` wave 12/13 review: issue DJ (unary minus applied to a non-numeric value silently passing through as Unknown) was intentionally skipped after v1 measurement showed libexec/hawk-check performs no type checking at all on return expressions, unconditionally allowing this pattern. This preserves v1 compatibility; stricter v2-only enforcement is deferred to the Task 12 v1-compatibility gate decision.

Learnt from: redpeacock78
URL: https://github.com/redpeacock78/H-awk/pull/108

Timestamp: 2026-07-03T17:54:25.714Z
Learning: In the redpeacock78/H-awk repository's DSL v2 implementation (dsl/v2/check.awk), as of PR `#108` waves 12-13 review: two reviewer-detected critical issues were fixed alongside DC-DV. C1: the shared helper used by issues DK/DL/DV (union-member Untrusted detection for interpolation and concatenation) did not resolve aliases per union member, so a single-level alias like `type U = Untrusted<Str>; x: Str|U` could bypass Untrusted propagation detection; fixed by routing each union member through v2_resolve_sealed before the Untrusted check. C2: the DT fix (accepting TYPE tokens in parameter position) failed to rescue uppercase-named parameters with no type annotation at all (e.g. `function handler(Raw) {...}`), which were dropped/lost during parameter parsing, silently bypassing Untrusted checks; the naming-heuristic approach (used by both DE and DT) was replaced with a structural marker where only the return-type OPERAND is prefixed with `->` during RPN conversion, removing ambiguity between parameter names and type annotations. This also fixed accidental parameter loss when multiple parameters were present. 13 existing fixtures' expected.rpn.tsv were updated to reflect the new RPN dump notation; ast/types stage fixtures were unaffected.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
dsl/v2/check.awk (3)

465-479: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

INDEX_ASSIGN の key 型も alias 解決してください。

v2_index_type() は key alias を解決していますが、代入側は raw TYPEOFInt / Str と比較するため、type Key = Str の key でも Dict 代入が誤 reject されます。

修正案
-  key_type = (idx_id != 0 && (idx_id in TYPEOF)) ? TYPEOF[idx_id] : ""
+  key_type = (idx_id != 0 && (idx_id in TYPEOF)) ? v2_resolve_sealed(TYPEOF[idx_id]) : ""
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dsl/v2/check.awk` around lines 465 - 479, The index-assignment checks in
v2/check.awk are using raw TYPEOF values for key_type, so alias types like type
Key = Str are not resolved and valid Dict assignments can be rejected. Update
the INDEX_ASSIGN path in the same logic that uses v2_index_type() behavior so
key_type is normalized through alias resolution before the List/Dict
compatibility checks, and keep the existing v2_diag messages intact while
comparing against the resolved key type.

939-948: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

補間内 call 境界で文字列リテラルを無視してください。

v2_match_call_close()) だけで深さを減らすため、#{safe.html.raw(\")\")} のような inner string 内の ) で call が途中終了します。v2_find_interp_close() と同じ \" トグルをここにも入れてください。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dsl/v2/check.awk` around lines 939 - 948, Update v2_match_call_close so it
ignores ) characters that appear inside escaped string literals while scanning
for the matching call close. The current depth tracking in v2_match_call_close
treats every ) as structural, so add the same backslash-quote toggle logic used
by v2_find_interp_close to track whether the scanner is inside a quoted string
before decrementing depth. Keep the fix localized to v2_match_call_close and
preserve the existing parenthesis depth behavior outside strings.

1031-1058: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

nested generic call も補間引数として検査してください。

ここだけ旧 regex のままなので、safe.html.raw(json.decode_t<Str>(...)) のような補間引数内 generic call が Unknown になり、arity/type/sealed 検査を迂回します。v2_interp_match_call_head() を使う経路に揃えるのが安全です。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dsl/v2/check.awk` around lines 1031 - 1058, The call-head parsing in the
interpolation path still uses the old regex-based match, so nested generic calls
inside interpolated arguments can slip through as Unknown and bypass
arity/type/sealed checks. Update the logic in the call handling around
v2_match_call_close and the SIG-based validation to use the same
v2_interp_match_call_head() flow as the rest of the interpreter, so nested
generic calls like json.decode_t<Str>(...) are recognized and validated
consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dsl/v2/check.awk`:
- Around line 241-248: The union member check in v2_type_has_untrusted_member
only inspects the original split parts, so alias expansion can hide sealed or
Untrusted members when v2_resolve_sealed returns a union. Update
v2_type_has_untrusted_member to resolve each member first and then re-run
v2_split_union on the resolved result before prefix checks, so aliases like U or
S are fully analyzed for every nested union member.

---

Outside diff comments:
In `@dsl/v2/check.awk`:
- Around line 465-479: The index-assignment checks in v2/check.awk are using raw
TYPEOF values for key_type, so alias types like type Key = Str are not resolved
and valid Dict assignments can be rejected. Update the INDEX_ASSIGN path in the
same logic that uses v2_index_type() behavior so key_type is normalized through
alias resolution before the List/Dict compatibility checks, and keep the
existing v2_diag messages intact while comparing against the resolved key type.
- Around line 939-948: Update v2_match_call_close so it ignores ) characters
that appear inside escaped string literals while scanning for the matching call
close. The current depth tracking in v2_match_call_close treats every ) as
structural, so add the same backslash-quote toggle logic used by
v2_find_interp_close to track whether the scanner is inside a quoted string
before decrementing depth. Keep the fix localized to v2_match_call_close and
preserve the existing parenthesis depth behavior outside strings.
- Around line 1031-1058: The call-head parsing in the interpolation path still
uses the old regex-based match, so nested generic calls inside interpolated
arguments can slip through as Unknown and bypass arity/type/sealed checks.
Update the logic in the call handling around v2_match_call_close and the
SIG-based validation to use the same v2_interp_match_call_head() flow as the
rest of the interpreter, so nested generic calls like json.decode_t<Str>(...)
are recognized and validated consistently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7b67f1dd-44fe-4e2c-9d5b-d354a0b27765

📥 Commits

Reviewing files that changed from the base of the PR and between e6edddb and cf4cdc5.

⛔ Files ignored due to path filters (22)
  • tests/dsl2/ast_let_bare/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/ast_let_bare_typed/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_arith_alias/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_exp_literal_float/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_index_key_alias/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_interp_brace_in_string_ok/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_param_uppercase_bare_ok/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_param_uppercase_ok/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_when_binder_alias/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/lex_leading_dot_float/expected.lex.tsv is excluded by !**/*.tsv
  • tests/dsl2/lex_leading_dot_float/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_arith_prec/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_call_dotted/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_expr_line_bound/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_func_brace_nextline/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_func_marker/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_nested_brace/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_rawline/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_rawstmt_print/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_regex_literal/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_two_assigns/expected.rpn.tsv is excluded by !**/*.tsv
  • tests/dsl2/rpn_when_marker/expected.rpn.tsv is excluded by !**/*.tsv
📒 Files selected for processing (50)
  • dsl/v2/check.awk
  • dsl/v2/lex.awk
  • dsl/v2/parse.awk
  • dsl/v2/rpn.awk
  • tests/dsl2/check_arith_alias/input.awk
  • tests/dsl2/check_exp_literal_float/input.awk
  • tests/dsl2/check_index_key_alias/input.awk
  • tests/dsl2/check_interp_brace_in_string_ok/input.awk
  • tests/dsl2/check_param_uppercase_bare_ok/input.awk
  • tests/dsl2/check_param_uppercase_ok/input.awk
  • tests/dsl2/check_return_alias_lowercase/expected_stderr
  • tests/dsl2/check_return_alias_lowercase/input.awk
  • tests/dsl2/check_when_binder_alias/input.awk
  • tests/dsl2/err_alias_cycle_intersection/expected_stderr
  • tests/dsl2/err_alias_cycle_intersection/input.awk
  • tests/dsl2/err_concat_union_alias_untrusted/expected_stderr
  • tests/dsl2/err_concat_union_alias_untrusted/input.awk
  • tests/dsl2/err_concat_union_untrusted/expected_stderr
  • tests/dsl2/err_concat_union_untrusted/input.awk
  • tests/dsl2/err_exp_literal_int/expected_stderr
  • tests/dsl2/err_exp_literal_int/input.awk
  • tests/dsl2/err_indexed_call_arg/expected_stderr
  • tests/dsl2/err_indexed_call_arg/input.awk
  • tests/dsl2/err_interp_brace_in_string/expected_stderr
  • tests/dsl2/err_interp_brace_in_string/input.awk
  • tests/dsl2/err_interp_generic_sealed/expected_stderr
  • tests/dsl2/err_interp_generic_sealed/input.awk
  • tests/dsl2/err_interp_nested_call_arg/expected_stderr
  • tests/dsl2/err_interp_nested_call_arg/input.awk
  • tests/dsl2/err_interp_paren_wrapped/expected_stderr
  • tests/dsl2/err_interp_paren_wrapped/input.awk
  • tests/dsl2/err_interp_pipe_arity/expected_stderr
  • tests/dsl2/err_interp_pipe_arity/input.awk
  • tests/dsl2/err_interp_union_alias_untrusted/expected_stderr
  • tests/dsl2/err_interp_union_alias_untrusted/input.awk
  • tests/dsl2/err_interp_union_untrusted/expected_stderr
  • tests/dsl2/err_interp_union_untrusted/input.awk
  • tests/dsl2/err_interp_unsupported_untrusted/expected_stderr
  • tests/dsl2/err_interp_unsupported_untrusted/input.awk
  • tests/dsl2/err_param_uppercase_bare_untrusted/expected_stderr
  • tests/dsl2/err_param_uppercase_bare_untrusted/input.awk
  • tests/dsl2/err_param_uppercase_untrusted/expected_stderr
  • tests/dsl2/err_param_uppercase_untrusted/input.awk
  • tests/dsl2/err_pipe_union_sealed/expected_stderr
  • tests/dsl2/err_pipe_union_sealed/input.awk
  • tests/dsl2/err_when_alias_union_coverage/expected_stderr
  • tests/dsl2/err_when_alias_union_coverage/input.awk
  • tests/dsl2/lex_leading_dot_float/input.awk
  • tests/dsl2/lex_regex_after_return/expected.awk
  • tests/dsl2/lex_regex_after_return/input.awk
✅ Files skipped from review due to trivial changes (22)
  • tests/dsl2/err_alias_cycle_intersection/expected_stderr
  • tests/dsl2/err_exp_literal_int/expected_stderr
  • tests/dsl2/err_when_alias_union_coverage/expected_stderr
  • tests/dsl2/err_indexed_call_arg/expected_stderr
  • tests/dsl2/err_interp_unsupported_untrusted/expected_stderr
  • tests/dsl2/err_interp_brace_in_string/expected_stderr
  • tests/dsl2/check_return_alias_lowercase/expected_stderr
  • tests/dsl2/check_exp_literal_float/input.awk
  • tests/dsl2/err_interp_generic_sealed/expected_stderr
  • tests/dsl2/err_alias_cycle_intersection/input.awk
  • tests/dsl2/lex_regex_after_return/input.awk
  • tests/dsl2/check_arith_alias/input.awk
  • tests/dsl2/err_concat_union_untrusted/expected_stderr
  • tests/dsl2/check_when_binder_alias/input.awk
  • tests/dsl2/err_param_uppercase_bare_untrusted/expected_stderr
  • tests/dsl2/err_interp_pipe_arity/input.awk
  • tests/dsl2/err_interp_paren_wrapped/expected_stderr
  • tests/dsl2/check_param_uppercase_ok/input.awk
  • tests/dsl2/err_interp_nested_call_arg/expected_stderr
  • tests/dsl2/err_interp_union_untrusted/input.awk
  • tests/dsl2/lex_leading_dot_float/input.awk
  • tests/dsl2/err_concat_union_alias_untrusted/expected_stderr
🚧 Files skipped from review as they are similar to previous changes (2)
  • dsl/v2/lex.awk
  • dsl/v2/rpn.awk

Comment thread dsl/v2/check.awk Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cf4cdc50cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread dsl/v2/check.awk Outdated
Comment thread dsl/v2/check.awk
Comment thread dsl/v2/check.awk Outdated
Comment thread dsl/v2/check.awk
Comment thread dsl/v2/check.awk Outdated
Comment thread dsl/v2/rpn.awk
Comment thread dsl/v2/rpn.awk Outdated
Comment thread dsl/v2/lex.awk
Comment thread dsl/v2/check.awk Outdated
Comment thread dsl/v2/check.awk
@redpeacock78

Copy link
Copy Markdown
Owner Author

Bot レビュー第 14+15 波(DW-EF、11 スレッド)対応完了

coderabbit の指摘 1 件(DW、Major)+ Codex bot の指摘 10 件(うち 1 件は DW と同一指摘)の計 10 項目を修正しました。加えてレビューアで検出した Critical 1 件 + Important 1 件を修正しています(28a8118..3c1820e の 5 コミット、fixture 174→190 件 green)。

第 14 波(coderabbit)

ID 指摘 対応
DW alias 展開結果が union の場合、v2_type_has_untrusted_member と pipe sealed 判定の prefix 照合が後続 member を見逃す 28a8118(共通ヘルパ v2_find_sealed_member(t, pat, depth) を新設。member の展開結果が元と異なる場合は union 再分割して再帰判定、depth<16 の循環ガード付き。3 経路すべてを置換)

第 15 波(Codex)

check.awk:247 の指摘は DW と同一のため上記に統合しています。

ID 指摘 対応
DX 補間内 pipe が classify: transform の dataflow 規則を適用せず Untrusted 未伝播 5d635b5(補間 pipe にも v2_dataflow_ret を適用)
DY 補間 call 実引数の未対応式が Unknown 素通りで Untrusted 未検査 5d635b5(DV と同じ Untrusted フォールバックを実引数型付けにも適用)
DZ fragment 補間のリテラル式が Unknown 扱いで HtmlPart 検査を素通り 5d635b5(Int/Float/Str リテラルの型を確定させ検査対象に)
EA エイリアス循環検出が generic 型引数内の循環(type A = List<B>; type B = A)を見逃す 5d635b5(循環 DFS を generic 引数内にも再帰)
EB 型付きコレクションの多次元 subscript xs["bad", 0] = 1 が先頭 key 欠落のまま素通り 2fc9ea8(添字内トップレベルカンマを診断で拒否)
EC 補間文字列を含む式文が一律 RAWLINE 化され brand/XSS 検査を素通り 2fc9ea8(let/return と同じく shunt 対象に。構造化不能な形は従来どおり RAWLINE の安全側を維持)
ED 次行ブレース関数の DSL 判定がブレース行自体をスキャンせず 1 行 body を見逃す 3fa3204(ブレース行もスキャン対象に)
EE classify 免除判定が未展開テキストの prefix 一致で、エイリアス越し Untrusted を誤拒否 5d635b5(DW のヘルパでエイリアス展開して照合)
EF 補間内 pipe に sealed 入力拒否(pipe input is <型>)が未適用 5d635b5(通常 PIPE と同じ sealed 拒否を適用、既存文言を使用)

レビューア検出分の修正

  • C1 (3c1820e, Critical): v2_dataflow_ret が入力型のエイリアスを展開せず、type U = Untrusted<Str> の入力で transform pipe が Untrusted を握り潰す XSS バイパス(通常 pipe と DX 新設の補間 pipe の両経路に影響)→ DW のヘルパを適用。両経路の共通関数のため 1 箇所の修正で閉鎖。
  • I1 (3c1820e, Important): 補間 pipe の classify 免除判定が EE と別 call site で旧 prefix 一致のまま残存し、エイリアス越し Untrusted で false positive → 同ヘルパを適用。

補足

  • 再レビューで同系統の prefix 照合を総ざらいした結果、残存 5 箇所はいずれも過剰制限方向(fail-safe)でバイパス性がないことを確認済みです。最終レビューの追跡候補として記録しています。

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

@redpeacock78 承知しました。第14+15波レビュー指摘(DW-EF)の対応内容を確認しました。

  • DW (Major): alias展開結果がunionになる場合のprefix照合漏れ、共通ヘルパv2_find_sealed_member(t, pat, depth)への統合(union再分割+循環ガード付き再帰)で3経路すべてを一貫して解消した設計、良いリファクタリングです。
  • DX/EE/EF: 補間pipeへのv2_dataflow_ret適用、classify免除判定のエイリアス展開、sealed入力拒否の適用、いずれも既存の通常pipe規則との整合性が取れています。
  • DY/DZ: 補間call実引数・fragmentリテラルのUnknown素通り解消、DVの既存フォールバックとの統一も確認しました。
  • EA: generic型引数内のエイリアス循環検出、DFSの再帰対象拡大、妥当です。
  • EB: 多次元subscriptの先頭key欠落問題、添字内トップレベルカンマの診断拒否、確認しました。
  • EC: 補間文字列を含む式文の一律RAWLINE化解消、let/returnと同じshunt対象化、構造化不能な形は安全側RAWLINE維持という切り分けも妥当です。
  • ED: 次行ブレース関数のDSL判定漏れ、ブレース行自体のスキャン追加、確認しました。

レビューア検出分(C1/I1)について

  • C1 (Critical): v2_dataflow_retが入力型のエイリアスを展開せず、transform pipeがUntrustedを握り潰すXSSバイパス、通常pipeと補間pipe両経路への影響を1箇所の共通関数修正で閉鎖した対応、重要な発見です。
  • I1 (Important): 補間pipeのclassify免除判定における別call siteでの旧prefix一致残存、同ヘルパでの統一修正、確認しました。

残存5箇所のprefix照合が過剰制限方向(fail-safe)でバイパス性がないことを確認済みとのこと、最終レビューの追跡候補として承知しました。

修正前worktreeでの再現確認プロセス、引き続き丁寧です。変更内容のレビューを実施します。

(=^・ω・^=)


✏️ Learnings added
Learnt from: redpeacock78
URL: https://github.com/redpeacock78/H-awk/pull/108

Timestamp: 2026-07-03T23:55:35.547Z
Learning: In the redpeacock78/H-awk repository's DSL v2 implementation (dsl/v2/check.awk), as of PR `#108` waves 14-15 review: a common helper `v2_find_sealed_member(t, pat, depth)` was introduced to fix issue DW (coderabbit), where alias expansion resulting in a union type caused prefix-matching logic in `v2_type_has_untrusted_member` and pipe sealed-input detection to miss later union members. The helper re-splits the union when a member's expanded form differs from the original, recursing with a depth<16 cycle guard, and replaced all 3 call sites. Additionally, two reviewer-detected issues were fixed using the same helper: C1 (Critical) - `v2_dataflow_ret` did not expand aliases on the input type, allowing a `type U = Untrusted<Str>` input to bypass Untrusted propagation through `classify: transform` pipes (affecting both regular and wave-15-introduced interpolation pipes); I1 (Important) - the interpolation pipe's classify-exemption check at a separate call site still used old prefix matching, causing false positives with aliased Untrusted types.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@dsl/v2/check.awk`:
- Around line 238-265: `v2_find_sealed_member` only walks union members, so
sealed checks miss `&` intersections such as alias-expanded `Tag &
Untrusted<Str>`. Update this helper to also split and recurse through
intersection members, using the existing intersection splitter pattern from
`v2_split_intersection` alongside `v2_split_union`, and keep the alias
resolution via `v2_resolve_sealed` plus the depth guard. This will ensure
`v2_type_has_untrusted_member` and the callers that rely on it
(`v2_check_pipe_rules`, `v2_check_brand_arg`, `v2_infer_interp_expr_type`)
correctly detect `Untrusted<...>` inside intersection aliases.

In `@tests/dsl2/err_alias_cycle_generic/expected_stderr`:
- Line 1: The stderr expectation is incomplete: it stops at the generic “type
alias cycle detected involving” message instead of including the concrete alias
name. Update the expected output for the alias-cycle test so it matches what
dsl/v2/check.awk emits by adding the specific type name after “involving”,
keeping the expectation aligned with the actual diagnostic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0d67d370-a2a7-4ab1-b138-ae353955cd62

📥 Commits

Reviewing files that changed from the base of the PR and between cf4cdc5 and 3c1820e.

⛔ Files ignored due to path filters (2)
  • tests/dsl2/check_classify_alias_untrusted_ok/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_interp_pipe_classify_alias_untrusted_ok/expected.types.tsv is excluded by !**/*.tsv
📒 Files selected for processing (33)
  • dsl/v2/check.awk
  • dsl/v2/lex.awk
  • dsl/v2/rpn.awk
  • tests/dsl2/check_awk_multidim_ok/expected.awk
  • tests/dsl2/check_awk_multidim_ok/input.awk
  • tests/dsl2/check_classify_alias_untrusted_ok/input.awk
  • tests/dsl2/check_interp_pipe_classify_alias_untrusted_ok/input.awk
  • tests/dsl2/err_alias_cycle_generic/expected_stderr
  • tests/dsl2/err_alias_cycle_generic/input.awk
  • tests/dsl2/err_brace_line_body_dsl/expected_stderr
  • tests/dsl2/err_brace_line_body_dsl/input.awk
  • tests/dsl2/err_concat_union_alias_2level_untrusted/expected_stderr
  • tests/dsl2/err_concat_union_alias_2level_untrusted/input.awk
  • tests/dsl2/err_concat_union_alias_nested_untrusted/expected_stderr
  • tests/dsl2/err_concat_union_alias_nested_untrusted/input.awk
  • tests/dsl2/err_fragment_interp_literal/expected_stderr
  • tests/dsl2/err_fragment_interp_literal/input.awk
  • tests/dsl2/err_index_comma_subscript/expected_stderr
  • tests/dsl2/err_index_comma_subscript/input.awk
  • tests/dsl2/err_interp_call_arg_untrusted_concat/expected_stderr
  • tests/dsl2/err_interp_call_arg_untrusted_concat/input.awk
  • tests/dsl2/err_interp_pipe_sealed/expected_stderr
  • tests/dsl2/err_interp_pipe_sealed/input.awk
  • tests/dsl2/err_interp_pipe_transform_untrusted/expected_stderr
  • tests/dsl2/err_interp_pipe_transform_untrusted/input.awk
  • tests/dsl2/err_interp_union_alias_nested_untrusted/expected_stderr
  • tests/dsl2/err_interp_union_alias_nested_untrusted/input.awk
  • tests/dsl2/err_pipe_transform_alias_untrusted/expected_stderr
  • tests/dsl2/err_pipe_transform_alias_untrusted/input.awk
  • tests/dsl2/err_pipe_union_alias_nested_sealed/expected_stderr
  • tests/dsl2/err_pipe_union_alias_nested_sealed/input.awk
  • tests/dsl2/err_stmt_interp_untrusted/expected_stderr
  • tests/dsl2/err_stmt_interp_untrusted/input.awk
✅ Files skipped from review due to trivial changes (8)
  • tests/dsl2/err_index_comma_subscript/expected_stderr
  • tests/dsl2/err_concat_union_alias_2level_untrusted/expected_stderr
  • tests/dsl2/err_interp_call_arg_untrusted_concat/expected_stderr
  • tests/dsl2/err_interp_pipe_transform_untrusted/expected_stderr
  • tests/dsl2/check_awk_multidim_ok/input.awk
  • tests/dsl2/err_concat_union_alias_nested_untrusted/expected_stderr
  • tests/dsl2/err_pipe_transform_alias_untrusted/expected_stderr
  • tests/dsl2/err_concat_union_alias_nested_untrusted/input.awk
🚧 Files skipped from review as they are similar to previous changes (2)
  • dsl/v2/lex.awk
  • dsl/v2/rpn.awk

Comment thread dsl/v2/check.awk
Comment thread tests/dsl2/err_alias_cycle_generic/expected_stderr Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3c1820e0ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread dsl/v2/check.awk
Comment thread dsl/v2/rpn.awk
Comment thread dsl/v2/check.awk Outdated
Comment thread dsl/v2/check.awk
Comment thread dsl/v2/lex.awk Outdated
Comment thread dsl/v2/check.awk Outdated
Comment thread dsl/v2/check.awk Outdated
Comment thread dsl/v2/rpn.awk
Comment thread dsl/v2/lex.awk
Comment thread dsl/v2/check.awk
redpeacock78 and others added 3 commits July 4, 2026 14:09
…・補間pipe後続テキスト・?=alias未展開を修正する(review EG,EH,EN,EO,ER)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@redpeacock78

Copy link
Copy Markdown
Owner Author

Bot レビュー第 16+17 波(EG-ER、12 スレッド)対応完了

coderabbit の指摘 2 件(EG, EH)+ Codex bot の指摘 10 件(EI-ER)のうち 9 件を修正し、3 件は v1 実測に基づきスキップしました(3c1820e..040c220 の 3 コミット、fixture 190→201 件 green)。

修正した項目

ID 指摘 対応
EG v2_find_sealed_member が union(|)しか分解せず、intersection(&)エイリアス越しの Untrusted/sealed を見逃す 9ebd5bf(member 展開結果を v2_split_intersection でも分割し各要素を再帰判定。generic 引数内の & は深さ考慮で誤分割しない)
EH err_alias_cycle_generic の expected_stderr が involving で切れて型名未検証 9ebd5bf(実出力どおり型名まで含めた)
EN 補間 pipe の RHS call 直後の後続テキストが未検査で、"#{raw |> safe.html.escape() raw}" の末尾 raw が素通り 9ebd5bf(非 pipe 分岐と同じ CONCAT 型付け規則を適用)
EJ DSL 関数内の複数行生 awk ブロックの閉じ } を関数終端と誤認し、以降の return 型検査が消失 233c1cf(RAWLINE の {/} 収支を関数スコープの深さカウンタで追跡)
EK 補間ネスト引数ヘルパが name<T>(...) 形式の generic call を認識せず Unknown 素通り 9ebd5bf(トップレベル側と同じ call head 認識に統一)
EM lex の DSL 検出正規表現に組込みエイリアス(Port/JsonValue/JsonObject/HtmlPart)が欠落 040c220(check.awk の組込み ALIAS 一覧と突合して追加)
EO ?= の nullable 判定が union member のエイリアスを展開せず、O|R 形式を誤 reject 9ebd5bf(member ごとに v2_resolve_sealed で展開してから判定)
EQ 未注釈関数の body が注釈付きユーザー関数呼び出しのみだと passthrough になり引数検査が消失 040c220(注釈付き関数名を事前収集し、その呼び出しを含む行を DSL 検査対象に昇格。v1 実測で診断が出ることを確認済み)
ER v2_type_compat が intersection を分解せず、Str & Any を満たす値も一律 reject 9ebd5bf(expected 側の intersection を分割し全 member 充足を要求)

スキップした項目(v1 互換維持)

ID 指摘 スキップ理由
EI transform の直接 CALL 経路が v2_dataflow_ret 未適用で declassify バイパス v1 実測で同型の抜け穴を確認済み(wave 14 の検証と同一根拠)。直接呼び出しへの dataflow 適用は v1 に無い規則で、既存 fixture と矛盾するため v1 互換ゲート(Task 12)の厳格化候補として記録
EL 値型関数の bare return が素通り wave 5 の AZ 修正で既に非 Void 関数の bare return を拒否済み。repro したところ error: function 'f' with return type ... の診断が出ることを確認(false positive)
EP 使用より後に宣言されたコレクションエイリアスの添字検査漏れ v1 実測で v1 も無診断(exit 0)を確認。v1 互換維持でコード変更なし、Task 12 の厳格化候補として記録

補足

  • レビューアで EG/ER の intersection 分解が Result<A & B, E> のような generic 引数内 & を誤分割しないことを個別検証済みです。
  • EQ の DSL 昇格メカニズムは理論上生 awk 構文と衝突する可能性があるため、Task 12 の実コードベース回帰確認の追跡項目に記録しています。

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

@redpeacock78 承知しました。第16+17波レビュー指摘12件(EG-ER)の対応内容を確認しました。

  • EG: v2_find_sealed_member の union のみ分解でintersection(&)越しのUntrusted/sealedを見逃していた件、v2_split_intersectionとの組み合わせでの再帰判定、generic引数内&の誤分割防止も含めて丁寧な修正です。
  • EH: err_alias_cycle_generic の expected_stderr が型名未検証で切れていた件、実出力どおりの検証強化、確認しました。
  • EN: 補間pipeのRHS call直後の後続テキスト未検査、非pipe分岐と同じCONCAT型付け規則の適用、妥当です。
  • EJ: DSL関数内の複数行生awkブロックの閉じ}誤認による関数終端誤判定、関数スコープの深さカウンタでの追跡、良い修正です。
  • EK: 補間ネスト引数ヘルパのgeneric call未認識、トップレベル側との統一、確認しました。
  • EM: lexのDSL検出正規表現における組込みエイリアス欠落、check.awkのALIAS一覧との突合、妥当です。
  • EO: ?=のnullable判定でunion member未展開だった件、member単位でのv2_resolve_sealed適用、確認しました。
  • EQ: 未注釈関数bodyが注釈付き関数呼び出しのみの場合のpassthrough漏れ、事前収集とDSL検査対象への昇格、v1実測での診断確認込みで妥当です。理論上の生awk構文との衝突可能性をTask 12の追跡項目に記録いただいた点も承知しました。
  • ER: v2_type_compatのintersection未分解によるreject漏れ、expected側の全member充足要求、確認しました。

スキップ項目(EI/EL/EP)について

  • EI: v1実測(wave 14と同一根拠)に基づくtransform直接CALL経路のスキップ、Task 12厳格化候補としての記録、これまでの方針と一貫しています。
  • EL: wave 5のAZ修正で既に解消済みであり、再現時に診断が出ることを確認したfalse positiveとのこと、了解しました。
  • EP: v1実測でv1自体も無診断(exit 0)を確認したうえでのv1互換維持、Task 12厳格化候補としての記録、承知しました。

EG/ERのintersection分解がgeneric引数内&を誤分割しないことの個別検証、EQのDSL昇格メカニズムの回帰確認追跡、いずれも丁寧なプロセスです。変更内容のレビューを実施します。

(=^・ω・^=)


✏️ Learnings added
Learnt from: redpeacock78
URL: https://github.com/redpeacock78/H-awk/pull/108

Timestamp: 2026-07-04T05:25:18.552Z
Learning: In the redpeacock78/H-awk repository's DSL v2 implementation (dsl/v2/check.awk), as of PR `#108` waves 16-17 review: issue EG (coderabbit) was fixed by extending `v2_find_sealed_member` to also split on intersection (`&`) via `v2_split_intersection`, not just union (`|`), recursing into each member when the expanded form differs from the original alias, while avoiding misinterpreting `&` inside generic type arguments (e.g., `Result<A & B, E>`) as a top-level split.

Learnt from: redpeacock78
URL: https://github.com/redpeacock78/H-awk/pull/108

Timestamp: 2026-07-04T05:25:18.552Z
Learning: In the redpeacock78/H-awk repository's DSL v2 implementation (dsl/v2/check.awk), as of PR `#108` waves 16-17 review, three issues were intentionally skipped to preserve v1 compatibility, deferred to the Task 12 v1-compatibility gate for stricter v2-only enforcement: EI (transform's direct CALL path not applying `v2_dataflow_ret`, allowing a declassify bypass, matching a v1 measured gap from wave 14), and EP (collection type aliases declared after use having their subscript checks skipped, matching v1's own exit-0/no-diagnostic behavior in this case). Issue EL (bare return on non-Void functions) was investigated but found to be a false positive — wave 5's AZ fix already rejects this pattern with a diagnostic, so no code change was needed.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
dsl/v2/lex.awk (1)

354-404: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

補間内でも文字列リテラルを字句化してください
dsl/v2/lex.awk:354-387 の補間スキャンには "v2_tok_str の分岐がなく、#{foo("x")} のような補間式内の文字列リテラルが OP 列に崩れます。#{expr} は式として扱う仕様なので、補間内でもネストした文字列を通常の v2_tok_str に渡す必要があります。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@dsl/v2/lex.awk` around lines 354 - 404, The interpolation scanner in v2
lexing is missing string-literal handling inside the #{...} expression path, so
quoted text like in v2_tok_str is currently broken into operator tokens. Update
the interpolation loop in lex.awk to detect a " character and delegate to
v2_tok_str just like the normal top-level tokenizer does, so nested strings
inside v2_push("INTERP_OPEN", ...) ... v2_push("INTERP_CLOSE", ...) are
tokenized correctly. Keep the existing handling for operators and words, but
ensure the interpolation branch preserves string tokens instead of treating them
as OP.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@dsl/v2/lex.awk`:
- Around line 354-404: The interpolation scanner in v2 lexing is missing
string-literal handling inside the #{...} expression path, so quoted text like
in v2_tok_str is currently broken into operator tokens. Update the interpolation
loop in lex.awk to detect a " character and delegate to v2_tok_str just like the
normal top-level tokenizer does, so nested strings inside v2_push("INTERP_OPEN",
...) ... v2_push("INTERP_CLOSE", ...) are tokenized correctly. Keep the existing
handling for operators and words, but ensure the interpolation branch preserves
string tokens instead of treating them as OP.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 32ceaeab-e8e0-4cd2-ac85-467ae0773435

📥 Commits

Reviewing files that changed from the base of the PR and between 3c1820e and 040c220.

⛔ Files ignored due to path filters (4)
  • tests/dsl2/check_func_raw_block_ok/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_intersection_compat_ok/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_letq_alias_union_ok/expected.types.tsv is excluded by !**/*.tsv
  • tests/dsl2/check_lex_param_builtin_alias/expected.lex.tsv is excluded by !**/*.tsv
📒 Files selected for processing (22)
  • dsl/v2/check.awk
  • dsl/v2/lex.awk
  • dsl/v2/rpn.awk
  • tests/dsl2/check_func_raw_block_ok/input.awk
  • tests/dsl2/check_intersection_compat_ok/input.awk
  • tests/dsl2/check_letq_alias_union_ok/input.awk
  • tests/dsl2/check_lex_param_builtin_alias/input.awk
  • tests/dsl2/err_alias_cycle_generic/expected_stderr
  • tests/dsl2/err_call_unannotated_caller/expected_stderr
  • tests/dsl2/err_call_unannotated_caller/input.awk
  • tests/dsl2/err_concat_intersection_alias_untrusted/expected_stderr
  • tests/dsl2/err_concat_intersection_alias_untrusted/input.awk
  • tests/dsl2/err_func_raw_block_return_mismatch/expected_stderr
  • tests/dsl2/err_func_raw_block_return_mismatch/input.awk
  • tests/dsl2/err_interp_nested_generic_sealed/expected_stderr
  • tests/dsl2/err_interp_nested_generic_sealed/input.awk
  • tests/dsl2/err_interp_pipe_trailing_untrusted/expected_stderr
  • tests/dsl2/err_interp_pipe_trailing_untrusted/input.awk
  • tests/dsl2/err_intersection_compat_ng/expected_stderr
  • tests/dsl2/err_intersection_compat_ng/input.awk
  • tests/dsl2/err_pipe_sealed_intersection_alias/expected_stderr
  • tests/dsl2/err_pipe_sealed_intersection_alias/input.awk
✅ Files skipped from review due to trivial changes (9)
  • tests/dsl2/err_func_raw_block_return_mismatch/expected_stderr
  • tests/dsl2/check_lex_param_builtin_alias/input.awk
  • tests/dsl2/err_call_unannotated_caller/expected_stderr
  • tests/dsl2/err_concat_intersection_alias_untrusted/expected_stderr
  • tests/dsl2/err_intersection_compat_ng/expected_stderr
  • tests/dsl2/err_interp_nested_generic_sealed/expected_stderr
  • tests/dsl2/err_call_unannotated_caller/input.awk
  • tests/dsl2/err_pipe_sealed_intersection_alias/expected_stderr
  • tests/dsl2/err_alias_cycle_generic/expected_stderr
🚧 Files skipped from review as they are similar to previous changes (2)
  • dsl/v2/rpn.awk
  • dsl/v2/check.awk

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant