背景
P4 評価器・emitter には「マッパーがAST化しきれない構造をソース文字列から手書きで再パースする」workaroundが多数ある。charAt / 手書き深さカウント(parenDepth/bracketDepth/braceDepth)/ splitTopLevel* / findMatching / *SourceSupport 等で、約17ファイル・~180箇所。
これらはパーサーコンビネータ基盤(unlaxer + 生成P4パーサー)の上に乗るプロジェクトとして筋が悪く、教育素材にもならない。生成された型安全AST(コンビネータの成果物)を単一の真実とし、消費側は eval(node.xxx()) で済むようにすべき。
正攻法サイクル(string比較で実証済み)
- workaround が補償しているマッパー欠陥を特定する
- その構造を マッパー側で正しくAST化(unlaxer-dsl の generate-sources 経路 = #43系の延長)
- workaround を削除し AST を直接利用
- 全パリティ/コーパス回帰で検証
実証例(完了)
string比較 toUpperCase('abc')=='ABC' が P4_DSL_JAVA_CODE で false になっていた件:
残対象(優先度順)
| workaround |
補償しているマッパー欠陥 |
規模 |
主なファイル |
tryEvaluateStructuredBinaryNode / renderNumericSourceSnippet |
数値leafがソース文字列のまま(proper node化されていない) |
大 |
P4TypedAstEvaluator, P4TypedJavaCodeEmitter, P4DefaultJavaCodeEmitter |
GeneratedP4ValueAstEvaluator / GeneratedP4NumberAstEvaluator(reflection safety-net) |
proper AST化で本来不要 |
大 |
evaluator/ast/GeneratedP4* |
P4SliceSourceSupport |
slice の start/end/step がAST化されない |
中 |
p4/P4SliceSourceSupport |
P4IfSourceSupport / P4TernarySourceSupport |
if/ternary の枝がAST化されない |
中 |
p4/P4IfSourceSupport, p4/P4TernarySourceSupport |
P4StrictMatchTypingValidator |
match型検査をヒューリスティック文字走査 |
中 |
evaluator/p4/P4StrictMatchTypingValidator |
P4PreferredAstMapper の手書き正規化/分割 |
各種 |
中 |
p4/P4PreferredAstMapper |
監査コマンド
```
grep -rln 'charAt(' src/main/java/org/unlaxer/tinyexpression/
grep -rln 'parenDepth|bracketDepth|braceDepth' src/main/java/org/unlaxer/tinyexpression/
grep -rln 'splitTopLevel|findMatching|unwrapWholeParentheses|SourceSnippet' src/main/java/org/unlaxer/tinyexpression/
```
受け入れ条件
- 各ノード型で「マッパーが正しいAST → 消費側は AST 直接利用」になり、対応する手書きスキャナが削除されている
- 全パリティ/コーパス/評価器テスト緑、fallback観測で退化なし
関連: #32 (fallback=0), #43 (unlaxer-parser, マッパー根治)
背景
P4 評価器・emitter には「マッパーがAST化しきれない構造をソース文字列から手書きで再パースする」workaroundが多数ある。
charAt/ 手書き深さカウント(parenDepth/bracketDepth/braceDepth)/splitTopLevel*/findMatching/*SourceSupport等で、約17ファイル・~180箇所。これらはパーサーコンビネータ基盤(unlaxer + 生成P4パーサー)の上に乗るプロジェクトとして筋が悪く、教育素材にもならない。生成された型安全AST(コンビネータの成果物)を単一の真実とし、消費側は
eval(node.xxx())で済むようにすべき。正攻法サイクル(string比較で実証済み)
実証例(完了)
string比較
toUpperCase('abc')=='ABC'が P4_DSL_JAVA_CODE で false になっていた件:findDescendantsが再帰的でfindDescendantByIndex(StringExpr,1)がネストの'abc'を拾っていたfindDescendantsをルールレベル収集に(unlaxer-parser PR handoff: P4 fallback=0 セッション (2026-06-27) — #32 codegen根治継続 (3.0.7/3.0.8/3.0.9 release) / 残り C=var宣言・型推論 #44,5de9eed)→node.left()/right()が正しくなったevalStringComparisonExprのソース分割workaround約130行(tryExtractStringComparisonFromSourceFormula/splitTopLevelStringComparison/resolveStringComparisonSide/tryEvaluateStringSourceSnippet/StringComparisonSource)を削除しeval(node.left())/eval(node.right())に(tinyexpression PR fix(p4): math関数算術 & variadic min/max を正答化 (closes #21; refs #22,#43) #34,c7132ab)残対象(優先度順)
tryEvaluateStructuredBinaryNode/renderNumericSourceSnippetP4TypedAstEvaluator,P4TypedJavaCodeEmitter,P4DefaultJavaCodeEmitterGeneratedP4ValueAstEvaluator/GeneratedP4NumberAstEvaluator(reflection safety-net)evaluator/ast/GeneratedP4*P4SliceSourceSupportp4/P4SliceSourceSupportP4IfSourceSupport/P4TernarySourceSupportp4/P4IfSourceSupport,p4/P4TernarySourceSupportP4StrictMatchTypingValidatorevaluator/p4/P4StrictMatchTypingValidatorP4PreferredAstMapperの手書き正規化/分割p4/P4PreferredAstMapper監査コマンド
```
grep -rln 'charAt(' src/main/java/org/unlaxer/tinyexpression/
grep -rln 'parenDepth|bracketDepth|braceDepth' src/main/java/org/unlaxer/tinyexpression/
grep -rln 'splitTopLevel|findMatching|unwrapWholeParentheses|SourceSnippet' src/main/java/org/unlaxer/tinyexpression/
```
受け入れ条件
関連: #32 (fallback=0), #43 (unlaxer-parser, マッパー根治)