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,286 @@
1
+ /*
2
+ * Konpeito JSON stdlib - yyjson wrapper
3
+ *
4
+ * Provides fast JSON parsing and generation using yyjson library.
5
+ */
6
+
7
+ #include <ruby.h>
8
+ #include "../../../../vendor/yyjson/yyjson.h"
9
+
10
+ /* Forward declarations */
11
+ static VALUE yyjson_val_to_ruby(yyjson_val *val);
12
+ static yyjson_mut_val *ruby_to_yyjson_mut(yyjson_mut_doc *doc, VALUE obj);
13
+
14
+ /* Convert yyjson value to Ruby VALUE (recursive) */
15
+ static VALUE yyjson_val_to_ruby(yyjson_val *val) {
16
+ if (!val) return Qnil;
17
+
18
+ yyjson_type type = yyjson_get_type(val);
19
+
20
+ switch (type) {
21
+ case YYJSON_TYPE_NULL:
22
+ return Qnil;
23
+
24
+ case YYJSON_TYPE_BOOL:
25
+ return yyjson_get_bool(val) ? Qtrue : Qfalse;
26
+
27
+ case YYJSON_TYPE_NUM:
28
+ if (yyjson_is_sint(val)) {
29
+ return LONG2NUM(yyjson_get_sint(val));
30
+ } else if (yyjson_is_uint(val)) {
31
+ return ULONG2NUM(yyjson_get_uint(val));
32
+ } else {
33
+ return DBL2NUM(yyjson_get_real(val));
34
+ }
35
+
36
+ case YYJSON_TYPE_STR: {
37
+ const char *str = yyjson_get_str(val);
38
+ size_t len = yyjson_get_len(val);
39
+ return rb_utf8_str_new(str, len);
40
+ }
41
+
42
+ case YYJSON_TYPE_ARR: {
43
+ VALUE arr = rb_ary_new();
44
+ yyjson_arr_iter iter;
45
+ yyjson_arr_iter_init(val, &iter);
46
+ yyjson_val *elem;
47
+ while ((elem = yyjson_arr_iter_next(&iter))) {
48
+ rb_ary_push(arr, yyjson_val_to_ruby(elem));
49
+ }
50
+ return arr;
51
+ }
52
+
53
+ case YYJSON_TYPE_OBJ: {
54
+ VALUE hash = rb_hash_new();
55
+ yyjson_obj_iter iter;
56
+ yyjson_obj_iter_init(val, &iter);
57
+ yyjson_val *key;
58
+ while ((key = yyjson_obj_iter_next(&iter))) {
59
+ yyjson_val *obj_val = yyjson_obj_iter_get_val(key);
60
+ const char *key_str = yyjson_get_str(key);
61
+ size_t key_len = yyjson_get_len(key);
62
+ rb_hash_aset(hash,
63
+ rb_utf8_str_new(key_str, key_len),
64
+ yyjson_val_to_ruby(obj_val));
65
+ }
66
+ return hash;
67
+ }
68
+
69
+ default:
70
+ return Qnil;
71
+ }
72
+ }
73
+
74
+ /* Convert Ruby VALUE to yyjson mutable value (recursive) */
75
+ static yyjson_mut_val *ruby_to_yyjson_mut(yyjson_mut_doc *doc, VALUE obj) {
76
+ if (NIL_P(obj)) {
77
+ return yyjson_mut_null(doc);
78
+ }
79
+
80
+ if (obj == Qtrue) {
81
+ return yyjson_mut_bool(doc, true);
82
+ }
83
+
84
+ if (obj == Qfalse) {
85
+ return yyjson_mut_bool(doc, false);
86
+ }
87
+
88
+ if (RB_INTEGER_TYPE_P(obj)) {
89
+ if (FIXNUM_P(obj)) {
90
+ return yyjson_mut_sint(doc, FIX2LONG(obj));
91
+ } else {
92
+ /* Bignum - try to convert to long long */
93
+ return yyjson_mut_sint(doc, NUM2LL(obj));
94
+ }
95
+ }
96
+
97
+ if (RB_FLOAT_TYPE_P(obj)) {
98
+ return yyjson_mut_real(doc, NUM2DBL(obj));
99
+ }
100
+
101
+ if (RB_TYPE_P(obj, T_STRING)) {
102
+ const char *str = RSTRING_PTR(obj);
103
+ size_t len = RSTRING_LEN(obj);
104
+ return yyjson_mut_strncpy(doc, str, len);
105
+ }
106
+
107
+ if (RB_TYPE_P(obj, T_SYMBOL)) {
108
+ VALUE str = rb_sym2str(obj);
109
+ const char *cstr = RSTRING_PTR(str);
110
+ size_t len = RSTRING_LEN(str);
111
+ return yyjson_mut_strncpy(doc, cstr, len);
112
+ }
113
+
114
+ if (RB_TYPE_P(obj, T_ARRAY)) {
115
+ yyjson_mut_val *arr = yyjson_mut_arr(doc);
116
+ long len = RARRAY_LEN(obj);
117
+ for (long i = 0; i < len; i++) {
118
+ VALUE elem = rb_ary_entry(obj, i);
119
+ yyjson_mut_val *mut_elem = ruby_to_yyjson_mut(doc, elem);
120
+ yyjson_mut_arr_append(arr, mut_elem);
121
+ }
122
+ return arr;
123
+ }
124
+
125
+ if (RB_TYPE_P(obj, T_HASH)) {
126
+ yyjson_mut_val *hash_obj = yyjson_mut_obj(doc);
127
+ VALUE keys = rb_funcall(obj, rb_intern("keys"), 0);
128
+ long len = RARRAY_LEN(keys);
129
+ for (long i = 0; i < len; i++) {
130
+ VALUE key = rb_ary_entry(keys, i);
131
+ VALUE val = rb_hash_aref(obj, key);
132
+
133
+ /* Convert key to string */
134
+ VALUE key_str;
135
+ if (RB_TYPE_P(key, T_STRING)) {
136
+ key_str = key;
137
+ } else if (RB_TYPE_P(key, T_SYMBOL)) {
138
+ key_str = rb_sym2str(key);
139
+ } else {
140
+ key_str = rb_funcall(key, rb_intern("to_s"), 0);
141
+ }
142
+
143
+ const char *key_cstr = RSTRING_PTR(key_str);
144
+ size_t key_len = RSTRING_LEN(key_str);
145
+ yyjson_mut_val *mut_key = yyjson_mut_strncpy(doc, key_cstr, key_len);
146
+ yyjson_mut_val *mut_val = ruby_to_yyjson_mut(doc, val);
147
+ yyjson_mut_obj_add(hash_obj, mut_key, mut_val);
148
+ }
149
+ return hash_obj;
150
+ }
151
+
152
+ /* For other objects, try to_json or to_s */
153
+ if (rb_respond_to(obj, rb_intern("to_json"))) {
154
+ VALUE json_str = rb_funcall(obj, rb_intern("to_json"), 0);
155
+ const char *str = RSTRING_PTR(json_str);
156
+ size_t len = RSTRING_LEN(json_str);
157
+ /* Parse and return as raw JSON */
158
+ yyjson_doc *inner_doc = yyjson_read(str, len, 0);
159
+ if (inner_doc) {
160
+ yyjson_val *root = yyjson_doc_get_root(inner_doc);
161
+ yyjson_mut_val *result = yyjson_val_mut_copy(doc, root);
162
+ yyjson_doc_free(inner_doc);
163
+ return result;
164
+ }
165
+ }
166
+
167
+ /* Fallback: convert to string */
168
+ VALUE str = rb_funcall(obj, rb_intern("to_s"), 0);
169
+ const char *cstr = RSTRING_PTR(str);
170
+ size_t len = RSTRING_LEN(str);
171
+ return yyjson_mut_strncpy(doc, cstr, len);
172
+ }
173
+
174
+ /*
175
+ * Parse JSON string to Ruby object
176
+ *
177
+ * @param json_string [String] JSON string to parse
178
+ * @return [Object] Ruby object (Hash, Array, String, Integer, Float, true, false, nil)
179
+ * @raise [ArgumentError] if JSON is invalid
180
+ */
181
+ VALUE konpeito_json_parse(VALUE self, VALUE json_string) {
182
+ Check_Type(json_string, T_STRING);
183
+
184
+ const char *str = RSTRING_PTR(json_string);
185
+ size_t len = RSTRING_LEN(json_string);
186
+
187
+ yyjson_read_err err;
188
+ yyjson_doc *doc = yyjson_read_opts((char *)str, len, 0, NULL, &err);
189
+
190
+ if (!doc) {
191
+ rb_raise(rb_eArgError, "JSON parse error at position %zu: %s",
192
+ err.pos, err.msg);
193
+ return Qnil;
194
+ }
195
+
196
+ yyjson_val *root = yyjson_doc_get_root(doc);
197
+ VALUE result = yyjson_val_to_ruby(root);
198
+
199
+ yyjson_doc_free(doc);
200
+ return result;
201
+ }
202
+
203
+ /*
204
+ * Generate JSON string from Ruby object
205
+ *
206
+ * @param obj [Object] Ruby object to convert
207
+ * @return [String] JSON string
208
+ */
209
+ VALUE konpeito_json_generate(VALUE self, VALUE obj) {
210
+ yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
211
+ if (!doc) {
212
+ rb_raise(rb_eNoMemError, "Failed to allocate JSON document");
213
+ return Qnil;
214
+ }
215
+
216
+ yyjson_mut_val *root = ruby_to_yyjson_mut(doc, obj);
217
+ yyjson_mut_doc_set_root(doc, root);
218
+
219
+ size_t len;
220
+ char *json_str = yyjson_mut_write(doc, 0, &len);
221
+
222
+ yyjson_mut_doc_free(doc);
223
+
224
+ if (!json_str) {
225
+ rb_raise(rb_eRuntimeError, "Failed to generate JSON");
226
+ return Qnil;
227
+ }
228
+
229
+ VALUE result = rb_utf8_str_new(json_str, len);
230
+ free(json_str);
231
+
232
+ return result;
233
+ }
234
+
235
+ /*
236
+ * Generate pretty-printed JSON string from Ruby object
237
+ *
238
+ * @param obj [Object] Ruby object to convert
239
+ * @param indent [Integer] indentation spaces (default: 2)
240
+ * @return [String] pretty-printed JSON string
241
+ */
242
+ VALUE konpeito_json_generate_pretty(VALUE self, VALUE obj, VALUE indent) {
243
+ int indent_spaces = NUM2INT(indent);
244
+ (void)indent_spaces; /* yyjson uses fixed 4-space indent for pretty print */
245
+
246
+ yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
247
+ if (!doc) {
248
+ rb_raise(rb_eNoMemError, "Failed to allocate JSON document");
249
+ return Qnil;
250
+ }
251
+
252
+ yyjson_mut_val *root = ruby_to_yyjson_mut(doc, obj);
253
+ yyjson_mut_doc_set_root(doc, root);
254
+
255
+ size_t len;
256
+ char *json_str = yyjson_mut_write(doc, YYJSON_WRITE_PRETTY, &len);
257
+
258
+ yyjson_mut_doc_free(doc);
259
+
260
+ if (!json_str) {
261
+ rb_raise(rb_eRuntimeError, "Failed to generate JSON");
262
+ return Qnil;
263
+ }
264
+
265
+ VALUE result = rb_utf8_str_new(json_str, len);
266
+ free(json_str);
267
+
268
+ return result;
269
+ }
270
+
271
+ /* Module initialization - called by Init_<extension_name> */
272
+ void Init_konpeito_json(void) {
273
+ VALUE mKonpeitoJSON = rb_define_module("KonpeitoJSON");
274
+
275
+ rb_define_module_function(mKonpeitoJSON, "parse", konpeito_json_parse, 1);
276
+ rb_define_module_function(mKonpeitoJSON, "generate", konpeito_json_generate, 1);
277
+ rb_define_module_function(mKonpeitoJSON, "generate_pretty", konpeito_json_generate_pretty, 2);
278
+
279
+ /* Parse flags as constants */
280
+ rb_define_const(mKonpeitoJSON, "ALLOW_COMMENTS",
281
+ UINT2NUM(YYJSON_READ_ALLOW_COMMENTS));
282
+ rb_define_const(mKonpeitoJSON, "ALLOW_TRAILING_COMMAS",
283
+ UINT2NUM(YYJSON_READ_ALLOW_TRAILING_COMMAS));
284
+ rb_define_const(mKonpeitoJSON, "ALLOW_INF_NAN",
285
+ UINT2NUM(YYJSON_READ_ALLOW_INF_AND_NAN));
286
+ }
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Build script for konpeito_ui native extension (SDL3 + Skia)
5
+ #
6
+ # Prerequisites:
7
+ # macOS:
8
+ # brew install sdl3
9
+ # Download Skia prebuilt (Aseprite m124):
10
+ # https://github.com/aseprite/skia/releases
11
+ # Set SKIA_DIR=~/skia-prebuilt (or wherever you extracted it)
12
+ #
13
+ # Linux:
14
+ # sudo apt install libsdl3-dev libgl-dev libfontconfig-dev libfreetype-dev
15
+ # Download/build Skia, set SKIA_DIR
16
+ #
17
+ # Windows (MSYS2):
18
+ # pacman -S mingw-w64-ucrt-x86_64-SDL3
19
+ # Download/build Skia, set SKIA_DIR
20
+ #
21
+ # Build:
22
+ # cd lib/konpeito/stdlib/ui && ruby extconf.rb && make
23
+
24
+ require "mkmf"
25
+
26
+ # C++17 required for Skia
27
+ # Aseprite Skia build uses -frtti (extra_cflags_cc = ["-frtti"])
28
+ $CXXFLAGS = ($CXXFLAGS || "") + " -std=c++17"
29
+ $CFLAGS = ($CFLAGS || "") + " -std=c11"
30
+
31
+ # Source file
32
+ $srcs = ["konpeito_ui_native.cpp"]
33
+
34
+ skia_dir = ENV["SKIA_DIR"] || File.expand_path("~/skia-prebuilt")
35
+
36
+ case RUBY_PLATFORM
37
+ when /darwin/
38
+ # macOS: SDL3 via Homebrew, Skia from SKIA_DIR
39
+ sdl_prefix = `brew --prefix sdl3 2>/dev/null`.chomp
40
+ if sdl_prefix.empty?
41
+ sdl_prefix = `pkg-config --variable=prefix sdl3 2>/dev/null`.chomp
42
+ end
43
+
44
+ unless sdl_prefix.empty?
45
+ $CFLAGS << " -I#{sdl_prefix}/include"
46
+ $CXXFLAGS << " -I#{sdl_prefix}/include"
47
+ $LDFLAGS << " -L#{sdl_prefix}/lib -lSDL3"
48
+ else
49
+ abort "SDL3 not found. Install with: brew install sdl3"
50
+ end
51
+
52
+ # Skia
53
+ if File.directory?(skia_dir)
54
+ # Include paths: top-level for "include/core/..." style includes
55
+ $INCFLAGS = "-I#{skia_dir} #{$INCFLAGS}"
56
+ $CXXFLAGS << " -I#{skia_dir}"
57
+
58
+ # Detect lib directory (Release-arm64, Release-x64, or Release)
59
+ skia_lib_dir = nil
60
+ ["Release-arm64", "Release-x64", "Release"].each do |d|
61
+ candidate = File.join(skia_dir, "out", d)
62
+ if File.exist?(File.join(candidate, "libskia.a"))
63
+ skia_lib_dir = candidate
64
+ break
65
+ end
66
+ end
67
+
68
+ unless skia_lib_dir
69
+ abort "libskia.a not found in #{skia_dir}/out/. Check your Skia build."
70
+ end
71
+
72
+ # Link Skia and its bundled dependencies
73
+ $LDFLAGS << " -L#{skia_lib_dir}"
74
+ # Order matters for static linking: dependents first, then dependencies
75
+ $LDFLAGS << " -lskia"
76
+ # Skia sub-libraries that are built separately in Aseprite's build
77
+ %w[harfbuzz freetype2 png zlib expat skcms webp].each do |lib|
78
+ lib_path = File.join(skia_lib_dir, "lib#{lib}.a")
79
+ if File.exist?(lib_path)
80
+ $LDFLAGS << " -l#{lib}"
81
+ end
82
+ end
83
+ else
84
+ abort "Skia not found at #{skia_dir}. Set SKIA_DIR environment variable."
85
+ end
86
+
87
+ # macOS frameworks for Metal + Cocoa + CoreText
88
+ $LDFLAGS << " -framework Metal -framework MetalKit -framework QuartzCore"
89
+ $LDFLAGS << " -framework Cocoa -framework IOKit -framework CoreFoundation"
90
+ $LDFLAGS << " -framework CoreGraphics -framework CoreText -framework CoreServices"
91
+ $LDFLAGS << " -framework Foundation -framework AppKit"
92
+
93
+ # Skia GPU backend defines (required for Metal/Ganesh headers)
94
+ $CXXFLAGS << " -DSK_GANESH -DSK_METAL"
95
+
96
+ # Objective-C++ support for Metal code
97
+ $CXXFLAGS << " -ObjC++"
98
+
99
+ # Suppress Skia deprecation warnings
100
+ $CXXFLAGS << " -Wno-deprecated-declarations"
101
+
102
+ when /linux/
103
+ # Linux: SDL3 via pkg-config, Skia from SKIA_DIR
104
+ sdl_cflags = `pkg-config --cflags sdl3 2>/dev/null`.chomp
105
+ sdl_libs = `pkg-config --libs sdl3 2>/dev/null`.chomp
106
+
107
+ if sdl_cflags.empty? && sdl_libs.empty?
108
+ abort "SDL3 not found. Install with: sudo apt install libsdl3-dev"
109
+ end
110
+
111
+ $CFLAGS << " " << sdl_cflags
112
+ $CXXFLAGS << " " << sdl_cflags
113
+ $LDFLAGS << " " << sdl_libs
114
+
115
+ # Skia
116
+ if File.directory?(skia_dir)
117
+ $INCFLAGS = "-I#{skia_dir} #{$INCFLAGS}"
118
+ $CXXFLAGS << " -I#{skia_dir}"
119
+
120
+ skia_lib_dir = nil
121
+ ["Release-x64", "Release"].each do |d|
122
+ candidate = File.join(skia_dir, "out", d)
123
+ if File.exist?(File.join(candidate, "libskia.a"))
124
+ skia_lib_dir = candidate
125
+ break
126
+ end
127
+ end
128
+ unless skia_lib_dir
129
+ abort "libskia.a not found in #{skia_dir}/out/"
130
+ end
131
+
132
+ $LDFLAGS << " -L#{skia_lib_dir} -lskia"
133
+ %w[harfbuzz freetype2 png zlib expat skcms webp].each do |lib|
134
+ lib_path = File.join(skia_lib_dir, "lib#{lib}.a")
135
+ $LDFLAGS << " -l#{lib}" if File.exist?(lib_path)
136
+ end
137
+ else
138
+ abort "Skia not found at #{skia_dir}. Set SKIA_DIR environment variable."
139
+ end
140
+
141
+ # Linux: OpenGL GPU backend + fontconfig
142
+ $LDFLAGS << " -lGL -lfontconfig -lfreetype"
143
+
144
+ # Skia GPU backend defines (required for OpenGL/Ganesh headers)
145
+ $CXXFLAGS << " -DSK_GANESH -DSK_GL"
146
+ $CXXFLAGS << " -Wno-deprecated-declarations"
147
+
148
+ when /mingw|mswin/
149
+ # Windows: SDL3 via MSYS2 or SDL3_DIR, Skia from SKIA_DIR
150
+ #
151
+ # MSYS2 setup:
152
+ # pacman -S mingw-w64-ucrt-x86_64-SDL3
153
+ #
154
+ # Or set SDL3_DIR to the SDL3 development folder.
155
+
156
+ sdl3_dir = ENV["SDL3_DIR"]
157
+ if sdl3_dir && File.directory?(sdl3_dir)
158
+ $CFLAGS << " -I#{sdl3_dir}/include"
159
+ $CXXFLAGS << " -I#{sdl3_dir}/include"
160
+ $LDFLAGS << " -L#{sdl3_dir}/lib -lSDL3"
161
+ else
162
+ # Try pkg-config (MSYS2 provides it)
163
+ sdl_cflags = `pkg-config --cflags sdl3 2>NUL`.chomp rescue ""
164
+ sdl_libs = `pkg-config --libs sdl3 2>NUL`.chomp rescue ""
165
+ if !sdl_cflags.empty? || !sdl_libs.empty?
166
+ $CFLAGS << " " << sdl_cflags unless sdl_cflags.empty?
167
+ $CXXFLAGS << " " << sdl_cflags unless sdl_cflags.empty?
168
+ $LDFLAGS << " " << sdl_libs unless sdl_libs.empty?
169
+ else
170
+ abort "SDL3 not found. Install with: pacman -S mingw-w64-ucrt-x86_64-SDL3\n" \
171
+ "Or set SDL3_DIR environment variable."
172
+ end
173
+ end
174
+
175
+ # Skia
176
+ if File.directory?(skia_dir)
177
+ $INCFLAGS = "-I#{skia_dir} #{$INCFLAGS}"
178
+ $CXXFLAGS << " -I#{skia_dir}"
179
+
180
+ skia_lib_dir = nil
181
+ ["Release-x64", "Release"].each do |d|
182
+ candidate = File.join(skia_dir, "out", d)
183
+ skia_lib = File.join(candidate, "skia.lib")
184
+ skia_lib_a = File.join(candidate, "libskia.a")
185
+ if File.exist?(skia_lib) || File.exist?(skia_lib_a)
186
+ skia_lib_dir = candidate
187
+ break
188
+ end
189
+ end
190
+ unless skia_lib_dir
191
+ abort "skia.lib/libskia.a not found in #{skia_dir}/out/"
192
+ end
193
+
194
+ $LDFLAGS << " -L#{skia_lib_dir} -lskia"
195
+ %w[harfbuzz freetype2 png zlib expat skcms webp].each do |lib|
196
+ lib_path_a = File.join(skia_lib_dir, "lib#{lib}.a")
197
+ lib_path_lib = File.join(skia_lib_dir, "#{lib}.lib")
198
+ $LDFLAGS << " -l#{lib}" if File.exist?(lib_path_a) || File.exist?(lib_path_lib)
199
+ end
200
+ else
201
+ abort "Skia not found at #{skia_dir}. Set SKIA_DIR environment variable."
202
+ end
203
+
204
+ # Windows: OpenGL + system libraries
205
+ $LDFLAGS << " -lopengl32 -lgdi32 -luser32"
206
+
207
+ # Skia GPU backend defines (required for OpenGL/Ganesh headers)
208
+ $CXXFLAGS << " -DSK_GANESH -DSK_GL"
209
+ $CXXFLAGS << " -Wno-deprecated-declarations"
210
+
211
+ else
212
+ abort "Unsupported platform: #{RUBY_PLATFORM}. macOS, Linux, and Windows (MSYS2) are supported."
213
+ end
214
+
215
+ # Create Makefile
216
+ create_makefile("konpeito_ui")