Module: BitClust::RbsOverloadMatcher
- Defined in:
- lib/bitclust/rbs_overload_matcher.rb
Class Method Summary collapse
-
.assign(overloads, chunks) ⇒ Object
overloads: rbs_sig JSON の overloads 配列(文字列キー Hash の配列) chunks: チャンクごとの正規化済みシグネチャ行("--- " 始まり)の配列 返り値: チャンクごとのオーバーロード添字の配列(chunks と同じ長さ).
-
.best_chunk(overload, features) ⇒ Object
---- 以下は実装詳細(module_function なので呼べてしまうが非公開扱い) ----.
-
.chunk_features(sig_lines) ⇒ Object
チャンクのシグネチャ行群から照合用の特徴を合算する。 1 行も解析できなければ nil(振り分け先にしない).
-
.overload_features(overload) ⇒ Object
rbs_sig JSON のオーバーロード 1 個からスコア用の特徴を取り出す。 メタ情報が無いもの(#322 以前の旧形式・attr・(?) 型)は nil.
-
.params_features(params) ⇒ Object
シグネチャの引数リスト文字列 → [最小アリティ, 最大アリティ(nil=無制限), 引数名(位置引数+キーワード名。**kwrest 名も含む), ブロック有無(&引数)].
-
.score(overload, chunk) ⇒ Object
ブロックの一致(または矛盾)を最優先に、引数名の一致 > アリティ範囲の 重なりで加点する。同点は先頭チャンク優先(best_chunk が > で更新).
-
.split_top_level(str) ⇒ Object
括弧((), [], {})のネストを無視して最上位の ',' で分割する (デフォルト値の中の ',' で切らないため).
Class Method Details
.assign(overloads, chunks) ⇒ Object
overloads: rbs_sig JSON の overloads 配列(文字列キー Hash の配列) chunks: チャンクごとの正規化済みシグネチャ行("--- " 始まり)の配列 返り値: チャンクごとのオーバーロード添字の配列(chunks と同じ長さ)
32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/bitclust/rbs_overload_matcher.rb', line 32 def assign(overloads, chunks) result = Array.new(chunks.size) { [] } #: Array[Array[Integer]] return result if chunks.empty? if chunks.size == 1 result[0] = (0...overloads.size).to_a return result end features = chunks.map {|lines| chunk_features(lines) } overloads.each_index do |i| ov = overload_features(overloads[i]) result[ov ? best_chunk(ov, features) : 0] << i end result end |
.best_chunk(overload, features) ⇒ Object
---- 以下は実装詳細(module_function なので呼べてしまうが非公開扱い) ----
88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/bitclust/rbs_overload_matcher.rb', line 88 def best_chunk(overload, features) best = 0 best_score = nil #: Integer? features.each_with_index do |chunk, i| next unless chunk s = score(overload, chunk) if best_score.nil? || s > best_score best = i best_score = s end end best end |
.chunk_features(sig_lines) ⇒ Object
チャンクのシグネチャ行群から照合用の特徴を合算する。 1 行も解析できなければ nil(振り分け先にしない)
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/bitclust/rbs_overload_matcher.rb', line 49 def chunk_features(sig_lines) names = [] #: Array[String] min = nil #: Integer? max = 0 #: Integer? block = false parsed = false sig_lines.each do |line| begin sig = MethodSignature.parse(line) rescue ParseError next end parsed = true block ||= !sig.block.nil? pmin, pmax, pnames, pblock = params_features(sig.params) block ||= pblock names.concat(pnames) min = pmin if min.nil? || pmin < min max = (max && pmax) ? [max, pmax].max : nil end return nil unless parsed { names: names, min: min || 0, max: max, block: block } end |
.overload_features(overload) ⇒ Object
rbs_sig JSON のオーバーロード 1 個からスコア用の特徴を取り出す。 メタ情報が無いもの(#322 以前の旧形式・attr・(?) 型)は nil
75 76 77 78 79 80 81 82 83 84 |
# File 'lib/bitclust/rbs_overload_matcher.rb', line 75 def overload_features(overload) arity = overload['arity'] params = overload['params'] block = overload['block'] return nil unless arity || params || block { names: params || [], min: arity && arity[0], max: arity && arity[1], block: block } end |
.params_features(params) ⇒ Object
シグネチャの引数リスト文字列 → [最小アリティ, 最大アリティ(nil=無制限), 引数名(位置引数+キーワード名。**kwrest 名も含む), ブロック有無(&引数)]
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/bitclust/rbs_overload_matcher.rb', line 125 def params_features(params) return [0, 0, [], false] if params.nil? || params.strip.empty? required = 0 optional = 0 rest = false block = false names = [] #: Array[String] split_top_level(params).each do |token| token = token.strip next if token.empty? name = token[/[A-Za-z_]\w*/] case token when /\A&/ block = true when /\A\*\*/ names << name if name when /\A\*/, '...' rest = true names << name if name when /\A[A-Za-z_]\w*:/ names << (name || raise) when /=/ optional += 1 names << name if name else required += 1 names << name if name end end [required, rest ? nil : required + optional, names, block] end |
.score(overload, chunk) ⇒ Object
ブロックの一致(または矛盾)を最優先に、引数名の一致 > アリティ範囲の 重なりで加点する。同点は先頭チャンク優先(best_chunk が > で更新)
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/bitclust/rbs_overload_matcher.rb', line 104 def score(overload, chunk) s = 0 case overload[:block] when 'req' s += chunk[:block] ? 2 : -3 when 'opt' s += 1 else s += chunk[:block] ? -3 : 2 end s += 2 * (overload[:names] & chunk[:names]).size if overload[:min] && chunk[:min] omax = overload[:max] || Float::INFINITY cmax = chunk[:max] || Float::INFINITY s += (overload[:min] <= cmax && chunk[:min] <= omax) ? 1 : -2 end s end |
.split_top_level(str) ⇒ Object
括弧((), [], {})のネストを無視して最上位の ',' で分割する (デフォルト値の中の ',' で切らないため)
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/bitclust/rbs_overload_matcher.rb', line 159 def split_top_level(str) tokens = [+''] #: Array[String] depth = 0 str.each_char do |c| case c when '(', '[', '{' then depth += 1 when ')', ']', '}' then depth -= 1 when ',' if depth == 0 tokens << +'' next end end tokens.last << c end tokens end |