konpeito 0.1.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.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG.md +75 -0
  4. data/CONTRIBUTING.md +123 -0
  5. data/LICENSE +21 -0
  6. data/README.md +257 -0
  7. data/Rakefile +11 -0
  8. data/bin/konpeito +6 -0
  9. data/konpeito.gemspec +43 -0
  10. data/lib/konpeito/ast/typed_ast.rb +620 -0
  11. data/lib/konpeito/ast/visitor.rb +78 -0
  12. data/lib/konpeito/cache/cache_manager.rb +230 -0
  13. data/lib/konpeito/cache/dependency_graph.rb +192 -0
  14. data/lib/konpeito/cache.rb +8 -0
  15. data/lib/konpeito/cli/base_command.rb +187 -0
  16. data/lib/konpeito/cli/build_command.rb +220 -0
  17. data/lib/konpeito/cli/check_command.rb +104 -0
  18. data/lib/konpeito/cli/config.rb +231 -0
  19. data/lib/konpeito/cli/deps_command.rb +128 -0
  20. data/lib/konpeito/cli/doctor_command.rb +340 -0
  21. data/lib/konpeito/cli/fmt_command.rb +199 -0
  22. data/lib/konpeito/cli/init_command.rb +312 -0
  23. data/lib/konpeito/cli/lsp_command.rb +40 -0
  24. data/lib/konpeito/cli/run_command.rb +150 -0
  25. data/lib/konpeito/cli/test_command.rb +248 -0
  26. data/lib/konpeito/cli/watch_command.rb +212 -0
  27. data/lib/konpeito/cli.rb +301 -0
  28. data/lib/konpeito/codegen/builtin_methods.rb +229 -0
  29. data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
  30. data/lib/konpeito/codegen/debug_info.rb +352 -0
  31. data/lib/konpeito/codegen/inliner.rb +486 -0
  32. data/lib/konpeito/codegen/jvm_backend.rb +197 -0
  33. data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
  34. data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
  35. data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
  36. data/lib/konpeito/codegen/monomorphizer.rb +359 -0
  37. data/lib/konpeito/codegen/profile_runtime.c +341 -0
  38. data/lib/konpeito/codegen/profiler.rb +99 -0
  39. data/lib/konpeito/compiler.rb +592 -0
  40. data/lib/konpeito/dependency_resolver.rb +296 -0
  41. data/lib/konpeito/diagnostics/collector.rb +127 -0
  42. data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
  43. data/lib/konpeito/diagnostics/renderer.rb +144 -0
  44. data/lib/konpeito/formatter/formatter.rb +1214 -0
  45. data/lib/konpeito/hir/builder.rb +7167 -0
  46. data/lib/konpeito/hir/nodes.rb +2465 -0
  47. data/lib/konpeito/lsp/document_manager.rb +820 -0
  48. data/lib/konpeito/lsp/server.rb +183 -0
  49. data/lib/konpeito/lsp/transport.rb +38 -0
  50. data/lib/konpeito/parser/prism_adapter.rb +65 -0
  51. data/lib/konpeito/platform.rb +103 -0
  52. data/lib/konpeito/profile/report.rb +136 -0
  53. data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
  54. data/lib/konpeito/stdlib/compression/compression.rb +72 -0
  55. data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
  56. data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
  57. data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
  58. data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
  59. data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
  60. data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
  61. data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
  62. data/lib/konpeito/stdlib/http/extconf.rb +19 -0
  63. data/lib/konpeito/stdlib/http/http.rb +125 -0
  64. data/lib/konpeito/stdlib/http/http.rbs +57 -0
  65. data/lib/konpeito/stdlib/http/http_native.c +440 -0
  66. data/lib/konpeito/stdlib/json/extconf.rb +17 -0
  67. data/lib/konpeito/stdlib/json/json.rb +44 -0
  68. data/lib/konpeito/stdlib/json/json.rbs +33 -0
  69. data/lib/konpeito/stdlib/json/json_native.c +286 -0
  70. data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
  71. data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
  72. data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
  73. data/lib/konpeito/stdlib/ui/ui.rb +318 -0
  74. data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
  75. data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
  76. data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
  77. data/lib/konpeito/type_checker/inferrer.rb +565 -0
  78. data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
  79. data/lib/konpeito/type_checker/type_resolver.rb +276 -0
  80. data/lib/konpeito/type_checker/types.rb +1434 -0
  81. data/lib/konpeito/type_checker/unification.rb +323 -0
  82. data/lib/konpeito/ui/animation/animated_state.rb +80 -0
  83. data/lib/konpeito/ui/animation/easing.rb +59 -0
  84. data/lib/konpeito/ui/animation/value_tween.rb +66 -0
  85. data/lib/konpeito/ui/app.rb +379 -0
  86. data/lib/konpeito/ui/box.rb +38 -0
  87. data/lib/konpeito/ui/castella.rb +70 -0
  88. data/lib/konpeito/ui/castella_native.rb +76 -0
  89. data/lib/konpeito/ui/chart/area_chart.rb +305 -0
  90. data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
  91. data/lib/konpeito/ui/chart/base_chart.rb +210 -0
  92. data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
  93. data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
  94. data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
  95. data/lib/konpeito/ui/chart/line_chart.rb +289 -0
  96. data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
  97. data/lib/konpeito/ui/chart/scales.rb +77 -0
  98. data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
  99. data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
  100. data/lib/konpeito/ui/column.rb +271 -0
  101. data/lib/konpeito/ui/core.rb +2199 -0
  102. data/lib/konpeito/ui/dsl.rb +443 -0
  103. data/lib/konpeito/ui/frame.rb +171 -0
  104. data/lib/konpeito/ui/frame_native.rb +494 -0
  105. data/lib/konpeito/ui/markdown/ast.rb +124 -0
  106. data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
  107. data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
  108. data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
  109. data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
  110. data/lib/konpeito/ui/markdown/parser.rb +805 -0
  111. data/lib/konpeito/ui/markdown/renderer.rb +639 -0
  112. data/lib/konpeito/ui/markdown/theme.rb +165 -0
  113. data/lib/konpeito/ui/render_node.rb +260 -0
  114. data/lib/konpeito/ui/row.rb +207 -0
  115. data/lib/konpeito/ui/spacer.rb +18 -0
  116. data/lib/konpeito/ui/style.rb +799 -0
  117. data/lib/konpeito/ui/theme.rb +563 -0
  118. data/lib/konpeito/ui/themes/material.rb +35 -0
  119. data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
  120. data/lib/konpeito/ui/widgets/button.rb +103 -0
  121. data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
  122. data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
  123. data/lib/konpeito/ui/widgets/container.rb +91 -0
  124. data/lib/konpeito/ui/widgets/data_table.rb +667 -0
  125. data/lib/konpeito/ui/widgets/divider.rb +29 -0
  126. data/lib/konpeito/ui/widgets/image.rb +105 -0
  127. data/lib/konpeito/ui/widgets/input.rb +485 -0
  128. data/lib/konpeito/ui/widgets/markdown.rb +57 -0
  129. data/lib/konpeito/ui/widgets/modal.rb +163 -0
  130. data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
  131. data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
  132. data/lib/konpeito/ui/widgets/net_image.rb +100 -0
  133. data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
  134. data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
  135. data/lib/konpeito/ui/widgets/slider.rb +133 -0
  136. data/lib/konpeito/ui/widgets/switch.rb +84 -0
  137. data/lib/konpeito/ui/widgets/tabs.rb +157 -0
  138. data/lib/konpeito/ui/widgets/text.rb +110 -0
  139. data/lib/konpeito/ui/widgets/tree.rb +426 -0
  140. data/lib/konpeito/version.rb +5 -0
  141. data/lib/konpeito.rb +109 -0
  142. data/test_native_array.rb +172 -0
  143. data/test_native_array_class.rb +197 -0
  144. data/test_native_class.rb +151 -0
  145. data/tools/konpeito-asm/build.sh +65 -0
  146. data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
  147. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
  148. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
  149. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
  150. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
  151. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
  152. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
  153. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
  154. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
  155. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
  156. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
  157. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
  158. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
  159. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
  160. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
  161. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
  162. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
  163. data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
  164. data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
  165. data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
  166. data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
  167. data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
  168. data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
  169. data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
  170. data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
  171. data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
  172. data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
  173. data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
  174. data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
  175. data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
  176. data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
  177. data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
  178. data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
  179. data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
  180. metadata +267 -0
@@ -0,0 +1,312 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module Konpeito
6
+ module Commands
7
+ # Init command - generates project structure
8
+ class InitCommand < BaseCommand
9
+ def self.command_name
10
+ "init"
11
+ end
12
+
13
+ def self.description
14
+ "Initialize a new Konpeito project"
15
+ end
16
+
17
+ def run
18
+ parse_options!
19
+
20
+ @project_name = args.first || File.basename(Dir.pwd)
21
+ @project_dir = args.first ? File.expand_path(@project_name, Dir.pwd) : Dir.pwd
22
+
23
+ if args.first && Dir.exist?(@project_dir)
24
+ # Allow if directory is empty, otherwise error
25
+ entries = Dir.entries(@project_dir) - %w[. ..]
26
+ unless entries.empty?
27
+ error("Directory '#{@project_name}' already exists and is not empty")
28
+ end
29
+ end
30
+
31
+ create_project_structure
32
+ puts "Project '#{@project_name}' initialized successfully!"
33
+ puts ""
34
+ puts "Next steps:"
35
+ puts " cd #{@project_name}" if args.first
36
+ if options[:target] == :jvm
37
+ puts " konpeito run src/main.rb"
38
+ puts " konpeito test"
39
+ else
40
+ puts " konpeito build src/main.rb"
41
+ puts " konpeito test"
42
+ end
43
+ end
44
+
45
+ protected
46
+
47
+ def default_options
48
+ {
49
+ verbose: false,
50
+ color: $stderr.tty?,
51
+ with_git: true,
52
+ target: :native
53
+ }
54
+ end
55
+
56
+ def setup_option_parser(opts)
57
+ opts.on("--no-git", "Do not create .gitignore") do
58
+ options[:with_git] = false
59
+ end
60
+
61
+ opts.on("--target TARGET", %i[native jvm], "Target platform (native, jvm)") do |target|
62
+ options[:target] = target
63
+ end
64
+
65
+ super
66
+ end
67
+
68
+ def banner
69
+ <<~BANNER.chomp
70
+ Usage: konpeito init [options] [project_name]
71
+
72
+ Examples:
73
+ konpeito init my_project Create native project
74
+ konpeito init --target jvm my_app Create JVM project
75
+ konpeito init Initialize current directory
76
+ BANNER
77
+ end
78
+
79
+ private
80
+
81
+ def create_project_structure
82
+ # Create directories
83
+ create_dir(@project_dir)
84
+ create_dir(File.join(@project_dir, "src"))
85
+ create_dir(File.join(@project_dir, "test"))
86
+
87
+ if options[:target] == :jvm
88
+ create_dir(File.join(@project_dir, "lib"))
89
+ create_jvm_config_file
90
+ create_jvm_main_rb
91
+ create_jvm_main_test
92
+ else
93
+ create_dir(File.join(@project_dir, "sig"))
94
+ create_config_file
95
+ create_main_rb
96
+ create_main_rbs
97
+ create_main_test
98
+ end
99
+
100
+ create_gitignore if options[:with_git]
101
+ puts_verbose "Created project structure in #{@project_dir}"
102
+ end
103
+
104
+ def create_dir(path)
105
+ return if Dir.exist?(path)
106
+
107
+ puts_verbose "Creating directory: #{path}"
108
+ FileUtils.mkdir_p(path)
109
+ end
110
+
111
+ def create_config_file
112
+ path = File.join(@project_dir, "konpeito.toml")
113
+ content = <<~TOML
114
+ # Konpeito project configuration
115
+ name = "#{@project_name}"
116
+ version = "0.1.0"
117
+
118
+ [build]
119
+ output = "#{@project_name}.bundle"
120
+ format = "cruby_ext"
121
+ rbs_paths = ["sig"]
122
+ require_paths = ["src"]
123
+ debug = false
124
+ profile = false
125
+ incremental = true
126
+
127
+ [test]
128
+ pattern = "test/**/*_test.rb"
129
+
130
+ [fmt]
131
+ indent = 2
132
+
133
+ [watch]
134
+ paths = ["src", "sig"]
135
+ extensions = ["rb", "rbs"]
136
+ TOML
137
+
138
+ write_file(path, content)
139
+ end
140
+
141
+ def create_main_rb
142
+ path = File.join(@project_dir, "src", "main.rb")
143
+ content = <<~RUBY
144
+ # frozen_string_literal: true
145
+
146
+ # Main module for #{@project_name}
147
+ module #{camelize(@project_name)}
148
+ def self.hello(name)
149
+ "Hello, " + name + "!"
150
+ end
151
+ end
152
+ RUBY
153
+
154
+ write_file(path, content)
155
+ end
156
+
157
+ def create_main_rbs
158
+ path = File.join(@project_dir, "sig", "main.rbs")
159
+ content = <<~RBS
160
+ # Type definitions for #{@project_name}
161
+ module #{camelize(@project_name)}
162
+ def self.hello: (String name) -> String
163
+ end
164
+ RBS
165
+
166
+ write_file(path, content)
167
+ end
168
+
169
+ def create_main_test
170
+ path = File.join(@project_dir, "test", "main_test.rb")
171
+ content = <<~RUBY
172
+ # frozen_string_literal: true
173
+
174
+ require "minitest/autorun"
175
+
176
+ class #{camelize(@project_name)}Test < Minitest::Test
177
+ def setup
178
+ # Load the compiled extension
179
+ # require_relative "../#{@project_name}"
180
+ end
181
+
182
+ def test_hello
183
+ # result = #{camelize(@project_name)}.hello("World")
184
+ # assert_equal "Hello, World!", result
185
+ skip "Compile with 'konpeito build src/main.rb' first"
186
+ end
187
+ end
188
+ RUBY
189
+
190
+ write_file(path, content)
191
+ end
192
+
193
+ def create_gitignore
194
+ path = File.join(@project_dir, ".gitignore")
195
+ lines = []
196
+ lines << "# Compiled extensions"
197
+ lines << "*.bundle"
198
+ lines << "*.so"
199
+ lines << "*.dll"
200
+ lines << "*.o"
201
+ lines << "*.dSYM/"
202
+
203
+ if options[:target] == :jvm
204
+ lines << ""
205
+ lines << "# JVM artifacts"
206
+ lines << "*.jar"
207
+ lines << "*.class"
208
+ lines << "lib/"
209
+ end
210
+
211
+ lines << ""
212
+ lines << "# Konpeito cache"
213
+ lines << ".konpeito_cache/"
214
+ lines << ""
215
+ lines << "# Profile output"
216
+ lines << "*_profile.json"
217
+ lines << "*.folded"
218
+ lines << ""
219
+ lines << "# Ruby"
220
+ lines << "*.gem"
221
+ lines << ".bundle/"
222
+ lines << "vendor/bundle/"
223
+ lines << ""
224
+ lines << "# IDE"
225
+ lines << ".idea/"
226
+ lines << ".vscode/"
227
+ lines << "*.swp"
228
+ lines << "*.swo"
229
+ lines << "*~"
230
+ lines << ""
231
+ lines << "# macOS"
232
+ lines << ".DS_Store"
233
+ lines << ""
234
+
235
+ write_file(path, lines.join("\n"))
236
+ end
237
+
238
+ def create_jvm_config_file
239
+ path = File.join(@project_dir, "konpeito.toml")
240
+ content = <<~TOML
241
+ # Konpeito JVM project configuration
242
+ name = "#{@project_name}"
243
+ version = "0.1.0"
244
+
245
+ [build]
246
+ target = "jvm"
247
+ output = "#{@project_name}.jar"
248
+ rbs_paths = []
249
+ require_paths = ["src"]
250
+
251
+ [jvm]
252
+ classpath = ""
253
+ java_home = ""
254
+ library = false
255
+
256
+ [deps]
257
+ jars = []
258
+
259
+ [test]
260
+ pattern = "test/**/*_test.rb"
261
+ TOML
262
+
263
+ write_file(path, content)
264
+ end
265
+
266
+ def create_jvm_main_rb
267
+ path = File.join(@project_dir, "src", "main.rb")
268
+ content = <<~RUBY
269
+ # Main entry point for #{@project_name}
270
+ def greet(name)
271
+ "Hello, " + name + "!"
272
+ end
273
+
274
+ puts greet("World")
275
+ RUBY
276
+
277
+ write_file(path, content)
278
+ end
279
+
280
+ def create_jvm_main_test
281
+ path = File.join(@project_dir, "test", "main_test.rb")
282
+ content = <<~RUBY
283
+ # Test for #{@project_name}
284
+ # Konpeito JVM tests use PASS:/FAIL: convention
285
+
286
+ def add(a, b)
287
+ a + b
288
+ end
289
+
290
+ result = add(2, 3)
291
+ if result == 5
292
+ puts "PASS: add returns correct sum"
293
+ else
294
+ puts "FAIL: add expected 5"
295
+ end
296
+ RUBY
297
+
298
+ write_file(path, content)
299
+ end
300
+
301
+ def write_file(path, content)
302
+ puts_verbose "Creating file: #{path}"
303
+ File.write(path, content)
304
+ end
305
+
306
+ def camelize(str)
307
+ str.gsub(/[-_](\w)/) { ::Regexp.last_match(1).upcase }
308
+ .sub(/^\w/) { ::Regexp.last_match(0).upcase }
309
+ end
310
+ end
311
+ end
312
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Konpeito
4
+ module Commands
5
+ # LSP command - starts the Language Server Protocol server
6
+ class LspCommand < BaseCommand
7
+ def self.command_name
8
+ "lsp"
9
+ end
10
+
11
+ def self.description
12
+ "Start Language Server Protocol server for IDE integration"
13
+ end
14
+
15
+ def run
16
+ parse_options!
17
+ start_lsp_server
18
+ end
19
+
20
+ protected
21
+
22
+ def setup_option_parser(opts)
23
+ super
24
+ end
25
+
26
+ def banner
27
+ "Usage: konpeito lsp [options]"
28
+ end
29
+
30
+ private
31
+
32
+ def start_lsp_server
33
+ puts_verbose "Starting LSP server..."
34
+ require_relative "../lsp/server"
35
+ server = LSP::Server.new
36
+ server.start
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Konpeito
4
+ module Commands
5
+ # Run command - build and execute in one step
6
+ class RunCommand < BaseCommand
7
+ def self.command_name
8
+ "run"
9
+ end
10
+
11
+ def self.description
12
+ "Build and run a Konpeito program"
13
+ end
14
+
15
+ def run
16
+ parse_options!
17
+
18
+ source_file = args.first
19
+ unless source_file
20
+ # Try to find default source from config or convention
21
+ source_file = find_default_source
22
+ unless source_file
23
+ error("No source file specified. Usage: konpeito run [options] <source.rb>")
24
+ end
25
+ end
26
+
27
+ unless File.exist?(source_file)
28
+ error("File not found: #{source_file}")
29
+ end
30
+
31
+ target = options[:target] || config.target
32
+
33
+ case target
34
+ when :jvm
35
+ run_jvm(source_file)
36
+ else
37
+ run_native(source_file)
38
+ end
39
+ end
40
+
41
+ protected
42
+
43
+ def default_options
44
+ {
45
+ verbose: false,
46
+ color: $stderr.tty?,
47
+ target: nil,
48
+ classpath: nil,
49
+ rbs_paths: config.rbs_paths.dup,
50
+ require_paths: config.require_paths.dup,
51
+ lib: false
52
+ }
53
+ end
54
+
55
+ def setup_option_parser(opts)
56
+ opts.on("--target TARGET", %i[native jvm], "Target platform (native, jvm)") do |target|
57
+ options[:target] = target
58
+ end
59
+
60
+ opts.on("--classpath PATH", "Add external JARs/directories to classpath (colon-separated)") do |path|
61
+ options[:classpath] = path
62
+ end
63
+
64
+ opts.on("--rbs FILE", "RBS type definition file (can be used multiple times)") do |file|
65
+ options[:rbs_paths] << file
66
+ end
67
+
68
+ opts.on("-I", "--require-path PATH", "Add require search path") do |path|
69
+ options[:require_paths] << path
70
+ end
71
+
72
+ super
73
+ end
74
+
75
+ def banner
76
+ <<~BANNER.chomp
77
+ Usage: konpeito run [options] [source.rb]
78
+
79
+ Examples:
80
+ konpeito run src/main.rb Build and run (native)
81
+ konpeito run --target jvm src/main.rb Build and run (JVM)
82
+ BANNER
83
+ end
84
+
85
+ private
86
+
87
+ def find_default_source
88
+ # Check common source locations
89
+ candidates = ["src/main.rb", "main.rb", "app.rb"]
90
+ candidates.find { |f| File.exist?(f) }
91
+ end
92
+
93
+ def run_jvm(source_file)
94
+ # Build classpath from config + options + lib/*.jar
95
+ classpath = build_classpath
96
+
97
+ # Build args for build command
98
+ build_args = build_jvm_args(source_file, classpath)
99
+ build_args << "--run"
100
+
101
+ Commands::BuildCommand.new(build_args, config: config).run
102
+ end
103
+
104
+ def run_native(source_file)
105
+ require "tmpdir"
106
+
107
+ output_file = File.join(Dir.tmpdir, "konpeito_run_#{File.basename(source_file, '.rb')}#{Platform.shared_lib_extension}")
108
+
109
+ build_args = ["-o", output_file]
110
+ build_args << "-v" if options[:verbose]
111
+ build_args << "--no-color" unless options[:color]
112
+ options[:rbs_paths].each { |p| build_args << "--rbs" << p }
113
+ options[:require_paths].each { |p| build_args << "-I" << p }
114
+ build_args << source_file
115
+
116
+ Commands::BuildCommand.new(build_args, config: config).run
117
+
118
+ emit("Running", output_file)
119
+ system("ruby", "-r", output_file, "-e", "")
120
+ ensure
121
+ FileUtils.rm_f(output_file) if output_file && File.exist?(output_file)
122
+ end
123
+
124
+ def build_classpath
125
+ parts = []
126
+
127
+ # From config
128
+ cp = options[:classpath] || config.jvm_classpath
129
+ parts << cp unless cp.empty?
130
+
131
+ # From lib/*.jar (downloaded dependencies)
132
+ lib_jars = Dir.glob("lib/*.jar")
133
+ parts << lib_jars.join(Platform.classpath_separator) unless lib_jars.empty?
134
+
135
+ parts.reject(&:empty?).join(Platform.classpath_separator)
136
+ end
137
+
138
+ def build_jvm_args(source_file, classpath)
139
+ build_args = ["--target", "jvm"]
140
+ build_args << "-v" if options[:verbose]
141
+ build_args << "--no-color" unless options[:color]
142
+ build_args += ["--classpath", classpath] unless classpath.empty?
143
+ options[:rbs_paths].each { |p| build_args << "--rbs" << p }
144
+ options[:require_paths].each { |p| build_args << "-I" << p }
145
+ build_args << source_file
146
+ build_args
147
+ end
148
+ end
149
+ end
150
+ end