konpeito 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +645 -0
- data/CHANGELOG.md +37 -0
- data/Justfile +107 -0
- data/README.md +143 -43
- data/konpeito.gemspec +3 -2
- data/lib/konpeito/cli/build_command.rb +21 -3
- data/lib/konpeito/cli/completion_command.rb +298 -0
- data/lib/konpeito/cli/deps_command.rb +129 -21
- data/lib/konpeito/cli/fmt_command.rb +24 -132
- data/lib/konpeito/cli/run_command.rb +29 -3
- data/lib/konpeito/cli.rb +45 -14
- data/lib/konpeito/codegen/builtin_methods.rb +16 -0
- data/lib/konpeito/codegen/cruby_backend.rb +76 -6
- data/lib/konpeito/codegen/jvm_generator.rb +100 -9
- data/lib/konpeito/codegen/llvm_generator.rb +907 -195
- data/lib/konpeito/dependency_resolver.rb +32 -9
- data/lib/konpeito/hir/builder.rb +369 -57
- data/lib/konpeito/hir/nodes.rb +25 -5
- data/lib/konpeito/type_checker/rbs_loader.rb +3 -2
- data/lib/konpeito/ui/app.rb +1 -1
- data/lib/konpeito/version.rb +1 -1
- data/lib/konpeito.rb +0 -7
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +32 -0
- metadata +6 -23
- data/lib/konpeito/cli/lsp_command.rb +0 -40
- data/lib/konpeito/formatter/formatter.rb +0 -1214
- data/lib/konpeito/lsp/document_manager.rb +0 -820
- data/lib/konpeito/lsp/server.rb +0 -183
- data/lib/konpeito/lsp/transport.rb +0 -38
- data/test_native_array.rb +0 -172
- data/test_native_array_class.rb +0 -197
- data/test_native_class.rb +0 -151
|
@@ -955,14 +955,24 @@ module Konpeito
|
|
|
955
955
|
}
|
|
956
956
|
elsif has_rescue
|
|
957
957
|
outer_br.rescue_clauses.each_with_index do |clause, i|
|
|
958
|
-
clause.exception_classes.
|
|
959
|
-
|
|
958
|
+
if clause.exception_classes.empty?
|
|
959
|
+
# Bare rescue → catch StandardError (Java Exception)
|
|
960
960
|
@pending_exception_table << {
|
|
961
961
|
"start" => try_start,
|
|
962
962
|
"end" => try_end,
|
|
963
963
|
"handler" => handler_labels[i],
|
|
964
|
-
"type" =>
|
|
964
|
+
"type" => "java/lang/Exception"
|
|
965
965
|
}
|
|
966
|
+
else
|
|
967
|
+
clause.exception_classes.each do |exc_class|
|
|
968
|
+
jvm_exc = ruby_exception_to_jvm(exc_class)
|
|
969
|
+
@pending_exception_table << {
|
|
970
|
+
"start" => try_start,
|
|
971
|
+
"end" => try_end,
|
|
972
|
+
"handler" => handler_labels[i],
|
|
973
|
+
"type" => jvm_exc
|
|
974
|
+
}
|
|
975
|
+
end
|
|
966
976
|
end
|
|
967
977
|
end
|
|
968
978
|
end
|
|
@@ -1313,6 +1323,8 @@ module Konpeito
|
|
|
1313
1323
|
generate_begin_rescue(inst)
|
|
1314
1324
|
when HIR::CaseStatement
|
|
1315
1325
|
generate_case_statement(inst)
|
|
1326
|
+
when HIR::CaseEqualityCheck
|
|
1327
|
+
generate_case_equality_check(inst)
|
|
1316
1328
|
when HIR::CaseMatchStatement
|
|
1317
1329
|
generate_case_match_statement(inst)
|
|
1318
1330
|
when HIR::LoadGlobalVar
|
|
@@ -2844,9 +2856,22 @@ module Konpeito
|
|
|
2844
2856
|
end
|
|
2845
2857
|
end
|
|
2846
2858
|
|
|
2847
|
-
#
|
|
2848
|
-
#
|
|
2849
|
-
|
|
2859
|
+
# Determine try body. If BeginRescue stores its own try_blocks, use those.
|
|
2860
|
+
# Pre-BeginRescue instructions (inlined_try_body) are only the try body when
|
|
2861
|
+
# the BeginRescue has no stored try_blocks (legacy HIR builder behavior).
|
|
2862
|
+
has_own_try = (inst.try_blocks && !inst.try_blocks.empty?) || (inst.try_hir_blocks && !inst.try_hir_blocks.empty?)
|
|
2863
|
+
pre_try_instructions = []
|
|
2864
|
+
if has_own_try
|
|
2865
|
+
# BeginRescue has its own try body. Pre-BeginRescue instructions that are NOT
|
|
2866
|
+
# already in try_blocks go BEFORE the try scope (e.g. variable initializations
|
|
2867
|
+
# before a begin/rescue block).
|
|
2868
|
+
try_body = inst.try_blocks || []
|
|
2869
|
+
try_block_ids = Set.new(try_body.map(&:object_id))
|
|
2870
|
+
pre_try_instructions = (inlined_try_body || []).reject { |i| try_block_ids.include?(i.object_id) }
|
|
2871
|
+
else
|
|
2872
|
+
# Legacy: pre-BeginRescue instructions ARE the try body
|
|
2873
|
+
try_body = (inlined_try_body && !inlined_try_body.empty?) ? inlined_try_body : []
|
|
2874
|
+
end
|
|
2850
2875
|
|
|
2851
2876
|
# If the begin/rescue has a result variable, pre-initialize it with null
|
|
2852
2877
|
result_var = inst.result_var
|
|
@@ -2874,6 +2899,11 @@ module Konpeito
|
|
|
2874
2899
|
# Label for exception ensure path (catch-all)
|
|
2875
2900
|
finally_handler_label = new_label("finally_handler") if has_ensure
|
|
2876
2901
|
|
|
2902
|
+
# 0. Emit pre-try instructions (code before begin/rescue that is NOT in the try scope)
|
|
2903
|
+
pre_try_instructions.each do |pre_inst|
|
|
2904
|
+
instructions.concat(generate_instruction(pre_inst))
|
|
2905
|
+
end
|
|
2906
|
+
|
|
2877
2907
|
# 1. Try block (generate BEFORE registering outer exception handlers,
|
|
2878
2908
|
# so that inner/nested BeginRescue handlers appear first in the table.
|
|
2879
2909
|
# JVM checks exception table entries in order; first match wins.)
|
|
@@ -2907,14 +2937,24 @@ module Konpeito
|
|
|
2907
2937
|
}
|
|
2908
2938
|
elsif has_rescue
|
|
2909
2939
|
inst.rescue_clauses.each_with_index do |clause, i|
|
|
2910
|
-
clause.exception_classes.
|
|
2911
|
-
|
|
2940
|
+
if clause.exception_classes.empty?
|
|
2941
|
+
# Bare rescue (no exception class) → catch StandardError (Java Exception)
|
|
2912
2942
|
@pending_exception_table << {
|
|
2913
2943
|
"start" => try_start,
|
|
2914
2944
|
"end" => try_end,
|
|
2915
2945
|
"handler" => handler_labels[i],
|
|
2916
|
-
"type" =>
|
|
2946
|
+
"type" => "java/lang/Exception"
|
|
2917
2947
|
}
|
|
2948
|
+
else
|
|
2949
|
+
clause.exception_classes.each do |exc_class|
|
|
2950
|
+
jvm_exc = ruby_exception_to_jvm(exc_class)
|
|
2951
|
+
@pending_exception_table << {
|
|
2952
|
+
"start" => try_start,
|
|
2953
|
+
"end" => try_end,
|
|
2954
|
+
"handler" => handler_labels[i],
|
|
2955
|
+
"type" => jvm_exc
|
|
2956
|
+
}
|
|
2957
|
+
end
|
|
2918
2958
|
end
|
|
2919
2959
|
end
|
|
2920
2960
|
end
|
|
@@ -3132,6 +3172,48 @@ module Konpeito
|
|
|
3132
3172
|
instructions
|
|
3133
3173
|
end
|
|
3134
3174
|
|
|
3175
|
+
# ========================================================================
|
|
3176
|
+
# CaseEqualityCheck (HIR node used by the block-based case/when)
|
|
3177
|
+
# ========================================================================
|
|
3178
|
+
|
|
3179
|
+
# Generate condition === predicate for case/when dispatch.
|
|
3180
|
+
# The condition is the when-value (e.g. 10, "hello") and the predicate is
|
|
3181
|
+
# the case expression (e.g. x). Result is stored as :i8 (boolean).
|
|
3182
|
+
# Uses load_value to either load from already-generated slot or generate inline.
|
|
3183
|
+
def generate_case_equality_check(inst)
|
|
3184
|
+
instructions = []
|
|
3185
|
+
result_var = inst.result_var
|
|
3186
|
+
|
|
3187
|
+
if inst.predicate.nil?
|
|
3188
|
+
# No predicate (bare `case; when cond then ...`): evaluate condition as truthy
|
|
3189
|
+
instructions.concat(load_value(inst.condition, :value))
|
|
3190
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
3191
|
+
"name" => "isTruthy", "descriptor" => "(Ljava/lang/Object;)Z" }
|
|
3192
|
+
if result_var
|
|
3193
|
+
ensure_slot(result_var, :i8)
|
|
3194
|
+
instructions << store_instruction(result_var, :i8)
|
|
3195
|
+
@variable_types[result_var.to_s] = :i8
|
|
3196
|
+
end
|
|
3197
|
+
else
|
|
3198
|
+
# condition === predicate: condition is the when value, predicate is the case expr.
|
|
3199
|
+
# Load condition (when value) — box to Object
|
|
3200
|
+
instructions.concat(load_value(inst.condition, :value))
|
|
3201
|
+
# Load predicate (case expression) — box to Object
|
|
3202
|
+
instructions.concat(load_value(inst.predicate, :value))
|
|
3203
|
+
# Call RubyDispatch.caseEqual(condition, predicate) → Z
|
|
3204
|
+
instructions << { "op" => "invokestatic", "owner" => "konpeito/runtime/RubyDispatch",
|
|
3205
|
+
"name" => "caseEqual",
|
|
3206
|
+
"descriptor" => "(Ljava/lang/Object;Ljava/lang/Object;)Z" }
|
|
3207
|
+
if result_var
|
|
3208
|
+
ensure_slot(result_var, :i8)
|
|
3209
|
+
instructions << store_instruction(result_var, :i8)
|
|
3210
|
+
@variable_types[result_var.to_s] = :i8
|
|
3211
|
+
end
|
|
3212
|
+
end
|
|
3213
|
+
|
|
3214
|
+
instructions
|
|
3215
|
+
end
|
|
3216
|
+
|
|
3135
3217
|
# ========================================================================
|
|
3136
3218
|
# case/when Statement
|
|
3137
3219
|
# ========================================================================
|
|
@@ -15243,6 +15325,15 @@ module Konpeito
|
|
|
15243
15325
|
incoming_types = phi.incoming.values.map do |val|
|
|
15244
15326
|
var = extract_var_name(val)
|
|
15245
15327
|
type = var ? @variable_types[var] : nil
|
|
15328
|
+
# For LoadInstanceVar, check the CLASS-LEVEL field type instead of HM annotation.
|
|
15329
|
+
# HM inference can produce incorrect types for ivars due to TypeVar pollution
|
|
15330
|
+
# (e.g., @font_family_val typed as Float instead of String).
|
|
15331
|
+
# The class field declaration is the source of truth.
|
|
15332
|
+
if type.nil? && val.is_a?(HIR::LoadInstanceVar) && @current_class_name
|
|
15333
|
+
field_name = val.name.to_s.sub(/^@/, "")
|
|
15334
|
+
ivar_info = resolve_ivar_info(field_name)
|
|
15335
|
+
type = ivar_info[:type] if ivar_info
|
|
15336
|
+
end
|
|
15246
15337
|
type || infer_type_from_hir(val) || literal_type_tag(val) || :value
|
|
15247
15338
|
end
|
|
15248
15339
|
|