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.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +75 -0
- data/CONTRIBUTING.md +123 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/Rakefile +11 -0
- data/bin/konpeito +6 -0
- data/konpeito.gemspec +43 -0
- data/lib/konpeito/ast/typed_ast.rb +620 -0
- data/lib/konpeito/ast/visitor.rb +78 -0
- data/lib/konpeito/cache/cache_manager.rb +230 -0
- data/lib/konpeito/cache/dependency_graph.rb +192 -0
- data/lib/konpeito/cache.rb +8 -0
- data/lib/konpeito/cli/base_command.rb +187 -0
- data/lib/konpeito/cli/build_command.rb +220 -0
- data/lib/konpeito/cli/check_command.rb +104 -0
- data/lib/konpeito/cli/config.rb +231 -0
- data/lib/konpeito/cli/deps_command.rb +128 -0
- data/lib/konpeito/cli/doctor_command.rb +340 -0
- data/lib/konpeito/cli/fmt_command.rb +199 -0
- data/lib/konpeito/cli/init_command.rb +312 -0
- data/lib/konpeito/cli/lsp_command.rb +40 -0
- data/lib/konpeito/cli/run_command.rb +150 -0
- data/lib/konpeito/cli/test_command.rb +248 -0
- data/lib/konpeito/cli/watch_command.rb +212 -0
- data/lib/konpeito/cli.rb +301 -0
- data/lib/konpeito/codegen/builtin_methods.rb +229 -0
- data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
- data/lib/konpeito/codegen/debug_info.rb +352 -0
- data/lib/konpeito/codegen/inliner.rb +486 -0
- data/lib/konpeito/codegen/jvm_backend.rb +197 -0
- data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
- data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
- data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
- data/lib/konpeito/codegen/monomorphizer.rb +359 -0
- data/lib/konpeito/codegen/profile_runtime.c +341 -0
- data/lib/konpeito/codegen/profiler.rb +99 -0
- data/lib/konpeito/compiler.rb +592 -0
- data/lib/konpeito/dependency_resolver.rb +296 -0
- data/lib/konpeito/diagnostics/collector.rb +127 -0
- data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
- data/lib/konpeito/diagnostics/renderer.rb +144 -0
- data/lib/konpeito/formatter/formatter.rb +1214 -0
- data/lib/konpeito/hir/builder.rb +7167 -0
- data/lib/konpeito/hir/nodes.rb +2465 -0
- data/lib/konpeito/lsp/document_manager.rb +820 -0
- data/lib/konpeito/lsp/server.rb +183 -0
- data/lib/konpeito/lsp/transport.rb +38 -0
- data/lib/konpeito/parser/prism_adapter.rb +65 -0
- data/lib/konpeito/platform.rb +103 -0
- data/lib/konpeito/profile/report.rb +136 -0
- data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
- data/lib/konpeito/stdlib/compression/compression.rb +72 -0
- data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
- data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
- data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
- data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
- data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
- data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
- data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
- data/lib/konpeito/stdlib/http/extconf.rb +19 -0
- data/lib/konpeito/stdlib/http/http.rb +125 -0
- data/lib/konpeito/stdlib/http/http.rbs +57 -0
- data/lib/konpeito/stdlib/http/http_native.c +440 -0
- data/lib/konpeito/stdlib/json/extconf.rb +17 -0
- data/lib/konpeito/stdlib/json/json.rb +44 -0
- data/lib/konpeito/stdlib/json/json.rbs +33 -0
- data/lib/konpeito/stdlib/json/json_native.c +286 -0
- data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
- data/lib/konpeito/stdlib/ui/ui.rb +318 -0
- data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
- data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
- data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
- data/lib/konpeito/type_checker/inferrer.rb +565 -0
- data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
- data/lib/konpeito/type_checker/type_resolver.rb +276 -0
- data/lib/konpeito/type_checker/types.rb +1434 -0
- data/lib/konpeito/type_checker/unification.rb +323 -0
- data/lib/konpeito/ui/animation/animated_state.rb +80 -0
- data/lib/konpeito/ui/animation/easing.rb +59 -0
- data/lib/konpeito/ui/animation/value_tween.rb +66 -0
- data/lib/konpeito/ui/app.rb +379 -0
- data/lib/konpeito/ui/box.rb +38 -0
- data/lib/konpeito/ui/castella.rb +70 -0
- data/lib/konpeito/ui/castella_native.rb +76 -0
- data/lib/konpeito/ui/chart/area_chart.rb +305 -0
- data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
- data/lib/konpeito/ui/chart/base_chart.rb +210 -0
- data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
- data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
- data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
- data/lib/konpeito/ui/chart/line_chart.rb +289 -0
- data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
- data/lib/konpeito/ui/chart/scales.rb +77 -0
- data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
- data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
- data/lib/konpeito/ui/column.rb +271 -0
- data/lib/konpeito/ui/core.rb +2199 -0
- data/lib/konpeito/ui/dsl.rb +443 -0
- data/lib/konpeito/ui/frame.rb +171 -0
- data/lib/konpeito/ui/frame_native.rb +494 -0
- data/lib/konpeito/ui/markdown/ast.rb +124 -0
- data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
- data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
- data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
- data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
- data/lib/konpeito/ui/markdown/parser.rb +805 -0
- data/lib/konpeito/ui/markdown/renderer.rb +639 -0
- data/lib/konpeito/ui/markdown/theme.rb +165 -0
- data/lib/konpeito/ui/render_node.rb +260 -0
- data/lib/konpeito/ui/row.rb +207 -0
- data/lib/konpeito/ui/spacer.rb +18 -0
- data/lib/konpeito/ui/style.rb +799 -0
- data/lib/konpeito/ui/theme.rb +563 -0
- data/lib/konpeito/ui/themes/material.rb +35 -0
- data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
- data/lib/konpeito/ui/widgets/button.rb +103 -0
- data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
- data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
- data/lib/konpeito/ui/widgets/container.rb +91 -0
- data/lib/konpeito/ui/widgets/data_table.rb +667 -0
- data/lib/konpeito/ui/widgets/divider.rb +29 -0
- data/lib/konpeito/ui/widgets/image.rb +105 -0
- data/lib/konpeito/ui/widgets/input.rb +485 -0
- data/lib/konpeito/ui/widgets/markdown.rb +57 -0
- data/lib/konpeito/ui/widgets/modal.rb +163 -0
- data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
- data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
- data/lib/konpeito/ui/widgets/net_image.rb +100 -0
- data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
- data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
- data/lib/konpeito/ui/widgets/slider.rb +133 -0
- data/lib/konpeito/ui/widgets/switch.rb +84 -0
- data/lib/konpeito/ui/widgets/tabs.rb +157 -0
- data/lib/konpeito/ui/widgets/text.rb +110 -0
- data/lib/konpeito/ui/widgets/tree.rb +426 -0
- data/lib/konpeito/version.rb +5 -0
- data/lib/konpeito.rb +109 -0
- data/test_native_array.rb +172 -0
- data/test_native_array_class.rb +197 -0
- data/test_native_class.rb +151 -0
- data/tools/konpeito-asm/build.sh +65 -0
- data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
- data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
- data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
- metadata +267 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
package konpeito.runtime;
|
|
2
|
+
|
|
3
|
+
import java.nio.charset.StandardCharsets;
|
|
4
|
+
import java.security.MessageDigest;
|
|
5
|
+
import java.security.SecureRandom;
|
|
6
|
+
import javax.crypto.Mac;
|
|
7
|
+
import javax.crypto.spec.SecretKeySpec;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* KCrypto - Cryptographic operations for Konpeito JVM backend.
|
|
11
|
+
* Maps to KonpeitoCrypto Ruby module.
|
|
12
|
+
* Uses java.security.* and javax.crypto.* (no external dependencies).
|
|
13
|
+
*/
|
|
14
|
+
public class KCrypto {
|
|
15
|
+
|
|
16
|
+
private static final SecureRandom SECURE_RANDOM = new SecureRandom();
|
|
17
|
+
private static final char[] HEX_CHARS = "0123456789abcdef".toCharArray();
|
|
18
|
+
|
|
19
|
+
// ========================================================================
|
|
20
|
+
// Hash Functions
|
|
21
|
+
// ========================================================================
|
|
22
|
+
|
|
23
|
+
/** KonpeitoCrypto.sha256(data) -> String (hex) */
|
|
24
|
+
public static String sha256(String data) {
|
|
25
|
+
return hexDigest("SHA-256", data);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** KonpeitoCrypto.sha512(data) -> String (hex) */
|
|
29
|
+
public static String sha512(String data) {
|
|
30
|
+
return hexDigest("SHA-512", data);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** KonpeitoCrypto.sha256_binary(data) -> String (binary via ISO-8859-1) */
|
|
34
|
+
public static String sha256Binary(String data) {
|
|
35
|
+
return binaryDigest("SHA-256", data);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** KonpeitoCrypto.sha512_binary(data) -> String (binary via ISO-8859-1) */
|
|
39
|
+
public static String sha512Binary(String data) {
|
|
40
|
+
return binaryDigest("SHA-512", data);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ========================================================================
|
|
44
|
+
// HMAC
|
|
45
|
+
// ========================================================================
|
|
46
|
+
|
|
47
|
+
/** KonpeitoCrypto.hmac_sha256(key, data) -> String (hex) */
|
|
48
|
+
public static String hmacSha256(String key, String data) {
|
|
49
|
+
return hexHmac("HmacSHA256", key, data);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** KonpeitoCrypto.hmac_sha512(key, data) -> String (hex) */
|
|
53
|
+
public static String hmacSha512(String key, String data) {
|
|
54
|
+
return hexHmac("HmacSHA512", key, data);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** KonpeitoCrypto.hmac_sha256_binary(key, data) -> String (binary) */
|
|
58
|
+
public static String hmacSha256Binary(String key, String data) {
|
|
59
|
+
return binaryHmac("HmacSHA256", key, data);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ========================================================================
|
|
63
|
+
// Random
|
|
64
|
+
// ========================================================================
|
|
65
|
+
|
|
66
|
+
/** KonpeitoCrypto.random_bytes(count) -> String (binary via ISO-8859-1) */
|
|
67
|
+
public static String randomBytes(long count) {
|
|
68
|
+
byte[] bytes = new byte[(int) Math.min(count, Integer.MAX_VALUE)];
|
|
69
|
+
SECURE_RANDOM.nextBytes(bytes);
|
|
70
|
+
return new String(bytes, StandardCharsets.ISO_8859_1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** KonpeitoCrypto.random_hex(count) -> String (hex, 2*count chars) */
|
|
74
|
+
public static String randomHex(long count) {
|
|
75
|
+
byte[] bytes = new byte[(int) Math.min(count, Integer.MAX_VALUE)];
|
|
76
|
+
SECURE_RANDOM.nextBytes(bytes);
|
|
77
|
+
return bytesToHex(bytes);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ========================================================================
|
|
81
|
+
// Comparison
|
|
82
|
+
// ========================================================================
|
|
83
|
+
|
|
84
|
+
/** KonpeitoCrypto.secure_compare(a, b) -> boolean (constant-time) */
|
|
85
|
+
public static boolean secureCompare(String a, String b) {
|
|
86
|
+
byte[] aBytes = a.getBytes(StandardCharsets.UTF_8);
|
|
87
|
+
byte[] bBytes = b.getBytes(StandardCharsets.UTF_8);
|
|
88
|
+
if (aBytes.length != bBytes.length) return false;
|
|
89
|
+
int result = 0;
|
|
90
|
+
for (int i = 0; i < aBytes.length; i++) {
|
|
91
|
+
result |= aBytes[i] ^ bBytes[i];
|
|
92
|
+
}
|
|
93
|
+
return result == 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ========================================================================
|
|
97
|
+
// Internal Helpers
|
|
98
|
+
// ========================================================================
|
|
99
|
+
|
|
100
|
+
private static String hexDigest(String algorithm, String data) {
|
|
101
|
+
try {
|
|
102
|
+
MessageDigest md = MessageDigest.getInstance(algorithm);
|
|
103
|
+
byte[] hash = md.digest(data.getBytes(StandardCharsets.UTF_8));
|
|
104
|
+
return bytesToHex(hash);
|
|
105
|
+
} catch (Exception e) {
|
|
106
|
+
throw new RuntimeException("Digest failed: " + e.getMessage(), e);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private static String binaryDigest(String algorithm, String data) {
|
|
111
|
+
try {
|
|
112
|
+
MessageDigest md = MessageDigest.getInstance(algorithm);
|
|
113
|
+
byte[] hash = md.digest(data.getBytes(StandardCharsets.UTF_8));
|
|
114
|
+
return new String(hash, StandardCharsets.ISO_8859_1);
|
|
115
|
+
} catch (Exception e) {
|
|
116
|
+
throw new RuntimeException("Digest failed: " + e.getMessage(), e);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private static String hexHmac(String algorithm, String key, String data) {
|
|
121
|
+
try {
|
|
122
|
+
Mac mac = Mac.getInstance(algorithm);
|
|
123
|
+
mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm));
|
|
124
|
+
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
|
|
125
|
+
return bytesToHex(hash);
|
|
126
|
+
} catch (Exception e) {
|
|
127
|
+
throw new RuntimeException("HMAC failed: " + e.getMessage(), e);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private static String binaryHmac(String algorithm, String key, String data) {
|
|
132
|
+
try {
|
|
133
|
+
Mac mac = Mac.getInstance(algorithm);
|
|
134
|
+
mac.init(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm));
|
|
135
|
+
byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
|
|
136
|
+
return new String(hash, StandardCharsets.ISO_8859_1);
|
|
137
|
+
} catch (Exception e) {
|
|
138
|
+
throw new RuntimeException("HMAC failed: " + e.getMessage(), e);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private static String bytesToHex(byte[] bytes) {
|
|
143
|
+
char[] hex = new char[bytes.length * 2];
|
|
144
|
+
for (int i = 0; i < bytes.length; i++) {
|
|
145
|
+
int v = bytes[i] & 0xFF;
|
|
146
|
+
hex[i * 2] = HEX_CHARS[v >>> 4];
|
|
147
|
+
hex[i * 2 + 1] = HEX_CHARS[v & 0x0F];
|
|
148
|
+
}
|
|
149
|
+
return new String(hex);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
package konpeito.runtime;
|
|
2
|
+
|
|
3
|
+
import java.io.IOException;
|
|
4
|
+
import java.nio.charset.StandardCharsets;
|
|
5
|
+
import java.nio.file.Files;
|
|
6
|
+
import java.nio.file.Path;
|
|
7
|
+
import java.util.List;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* KFile - File I/O operations for Konpeito JVM backend.
|
|
11
|
+
* Maps to KonpeitoFile Ruby module (JVM-only).
|
|
12
|
+
* Uses java.nio.file.* (Java 7+).
|
|
13
|
+
*/
|
|
14
|
+
public class KFile {
|
|
15
|
+
|
|
16
|
+
/** KonpeitoFile.read(path) -> String */
|
|
17
|
+
public static String read(String path) {
|
|
18
|
+
try {
|
|
19
|
+
return Files.readString(Path.of(path), StandardCharsets.UTF_8);
|
|
20
|
+
} catch (IOException e) {
|
|
21
|
+
throw new RuntimeException("File read failed: " + e.getMessage(), e);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** KonpeitoFile.write(path, content) -> String (content) */
|
|
26
|
+
public static String write(String path, String content) {
|
|
27
|
+
try {
|
|
28
|
+
Files.writeString(Path.of(path), content, StandardCharsets.UTF_8);
|
|
29
|
+
return content;
|
|
30
|
+
} catch (IOException e) {
|
|
31
|
+
throw new RuntimeException("File write failed: " + e.getMessage(), e);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** KonpeitoFile.exist?(path) -> boolean */
|
|
36
|
+
public static boolean exists(String path) {
|
|
37
|
+
return Files.exists(Path.of(path));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** KonpeitoFile.delete(path) -> boolean */
|
|
41
|
+
public static boolean delete(String path) {
|
|
42
|
+
try {
|
|
43
|
+
return Files.deleteIfExists(Path.of(path));
|
|
44
|
+
} catch (IOException e) {
|
|
45
|
+
throw new RuntimeException("File delete failed: " + e.getMessage(), e);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** KonpeitoFile.size(path) -> long */
|
|
50
|
+
public static long size(String path) {
|
|
51
|
+
try {
|
|
52
|
+
return Files.size(Path.of(path));
|
|
53
|
+
} catch (IOException e) {
|
|
54
|
+
throw new RuntimeException("File size failed: " + e.getMessage(), e);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** KonpeitoFile.readlines(path) -> KArray<String> */
|
|
59
|
+
public static KArray<String> readlines(String path) {
|
|
60
|
+
try {
|
|
61
|
+
List<String> lines = Files.readAllLines(Path.of(path), StandardCharsets.UTF_8);
|
|
62
|
+
KArray<String> result = new KArray<>();
|
|
63
|
+
for (String line : lines) {
|
|
64
|
+
result.add(line);
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
} catch (IOException e) {
|
|
68
|
+
throw new RuntimeException("File readlines failed: " + e.getMessage(), e);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** KonpeitoFile.basename(path) -> String */
|
|
73
|
+
public static String basename(String path) {
|
|
74
|
+
Path p = Path.of(path).getFileName();
|
|
75
|
+
return p != null ? p.toString() : "";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** KonpeitoFile.dirname(path) -> String */
|
|
79
|
+
public static String dirname(String path) {
|
|
80
|
+
Path p = Path.of(path).getParent();
|
|
81
|
+
return p != null ? p.toString() : ".";
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** KonpeitoFile.extname(path) -> String */
|
|
85
|
+
public static String extname(String path) {
|
|
86
|
+
String name = Path.of(path).getFileName().toString();
|
|
87
|
+
int dot = name.lastIndexOf('.');
|
|
88
|
+
return dot > 0 ? name.substring(dot) : "";
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** KonpeitoFile.mkdir(path) -> boolean */
|
|
92
|
+
public static boolean mkdir(String path) {
|
|
93
|
+
try {
|
|
94
|
+
Files.createDirectories(Path.of(path));
|
|
95
|
+
return true;
|
|
96
|
+
} catch (IOException e) {
|
|
97
|
+
throw new RuntimeException("mkdir failed: " + e.getMessage(), e);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
package konpeito.runtime;
|
|
2
|
+
|
|
3
|
+
import java.net.URI;
|
|
4
|
+
import java.net.http.HttpClient;
|
|
5
|
+
import java.net.http.HttpRequest;
|
|
6
|
+
import java.net.http.HttpResponse;
|
|
7
|
+
import java.time.Duration;
|
|
8
|
+
import java.util.Map;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* KHTTP - HTTP client for Konpeito JVM backend.
|
|
12
|
+
* Maps to KonpeitoHTTP Ruby module.
|
|
13
|
+
* Uses java.net.http.HttpClient (Java 11+).
|
|
14
|
+
*/
|
|
15
|
+
public class KHTTP {
|
|
16
|
+
private static final HttpClient CLIENT = HttpClient.newBuilder()
|
|
17
|
+
.followRedirects(HttpClient.Redirect.NORMAL)
|
|
18
|
+
.connectTimeout(Duration.ofSeconds(30))
|
|
19
|
+
.build();
|
|
20
|
+
|
|
21
|
+
/** KonpeitoHTTP.get(url) -> String (body) */
|
|
22
|
+
public static String get(String url) {
|
|
23
|
+
try {
|
|
24
|
+
HttpRequest request = HttpRequest.newBuilder()
|
|
25
|
+
.uri(URI.create(url))
|
|
26
|
+
.timeout(Duration.ofSeconds(30))
|
|
27
|
+
.GET()
|
|
28
|
+
.build();
|
|
29
|
+
HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
|
|
30
|
+
return response.body();
|
|
31
|
+
} catch (Exception e) {
|
|
32
|
+
throw new RuntimeException("HTTP GET failed: " + e.getMessage(), e);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** KonpeitoHTTP.post(url, body) -> String (body) */
|
|
37
|
+
public static String post(String url, String body) {
|
|
38
|
+
try {
|
|
39
|
+
HttpRequest request = HttpRequest.newBuilder()
|
|
40
|
+
.uri(URI.create(url))
|
|
41
|
+
.timeout(Duration.ofSeconds(30))
|
|
42
|
+
.POST(HttpRequest.BodyPublishers.ofString(body != null ? body : ""))
|
|
43
|
+
.header("Content-Type", "application/json")
|
|
44
|
+
.build();
|
|
45
|
+
HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
|
|
46
|
+
return response.body();
|
|
47
|
+
} catch (Exception e) {
|
|
48
|
+
throw new RuntimeException("HTTP POST failed: " + e.getMessage(), e);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** KonpeitoHTTP.get_response(url) -> KHash {status, body, headers} */
|
|
53
|
+
@SuppressWarnings("unchecked")
|
|
54
|
+
public static KHash<String, Object> getResponse(String url) {
|
|
55
|
+
try {
|
|
56
|
+
HttpRequest request = HttpRequest.newBuilder()
|
|
57
|
+
.uri(URI.create(url))
|
|
58
|
+
.timeout(Duration.ofSeconds(30))
|
|
59
|
+
.GET()
|
|
60
|
+
.build();
|
|
61
|
+
HttpResponse<String> response = CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
|
|
62
|
+
return buildResponseHash(response);
|
|
63
|
+
} catch (Exception e) {
|
|
64
|
+
throw new RuntimeException("HTTP GET failed: " + e.getMessage(), e);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** KonpeitoHTTP.request(method, url, body, headers) -> KHash */
|
|
69
|
+
@SuppressWarnings("unchecked")
|
|
70
|
+
public static KHash<String, Object> request(String method, String url, String body, KHash<String, String> headers) {
|
|
71
|
+
try {
|
|
72
|
+
HttpRequest.Builder builder = HttpRequest.newBuilder()
|
|
73
|
+
.uri(URI.create(url))
|
|
74
|
+
.timeout(Duration.ofSeconds(30));
|
|
75
|
+
|
|
76
|
+
// Set method and body
|
|
77
|
+
if (body != null && !body.isEmpty()) {
|
|
78
|
+
builder.method(method.toUpperCase(), HttpRequest.BodyPublishers.ofString(body));
|
|
79
|
+
} else {
|
|
80
|
+
builder.method(method.toUpperCase(), HttpRequest.BodyPublishers.noBody());
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Set custom headers
|
|
84
|
+
if (headers != null) {
|
|
85
|
+
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
|
86
|
+
builder.header(entry.getKey(), entry.getValue());
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
HttpResponse<String> response = CLIENT.send(builder.build(), HttpResponse.BodyHandlers.ofString());
|
|
91
|
+
return buildResponseHash(response);
|
|
92
|
+
} catch (Exception e) {
|
|
93
|
+
throw new RuntimeException("HTTP request failed: " + e.getMessage(), e);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@SuppressWarnings("unchecked")
|
|
98
|
+
private static KHash<String, Object> buildResponseHash(HttpResponse<String> response) {
|
|
99
|
+
KHash<String, Object> result = new KHash<>();
|
|
100
|
+
result.put("status", (long) response.statusCode());
|
|
101
|
+
result.put("body", response.body());
|
|
102
|
+
|
|
103
|
+
// Build headers hash
|
|
104
|
+
KHash<String, Object> headersHash = new KHash<>();
|
|
105
|
+
response.headers().map().forEach((key, values) -> {
|
|
106
|
+
if (!values.isEmpty()) {
|
|
107
|
+
headersHash.put(key, values.get(0));
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
result.put("headers", headersHash);
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
package konpeito.runtime;
|
|
2
|
+
|
|
3
|
+
import java.util.*;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* KHash - Ruby Hash implementation for JVM backend.
|
|
7
|
+
*
|
|
8
|
+
* Implements java.util.Map<K,V> via composition (wrapping LinkedHashMap<K,V>),
|
|
9
|
+
* providing both Java collection interop and Ruby-specific methods.
|
|
10
|
+
* LinkedHashMap preserves insertion order, matching Ruby Hash semantics.
|
|
11
|
+
*
|
|
12
|
+
* @param <K> Key type
|
|
13
|
+
* @param <V> Value type
|
|
14
|
+
*/
|
|
15
|
+
public class KHash<K, V> implements Map<K, V> {
|
|
16
|
+
private final LinkedHashMap<K, V> data;
|
|
17
|
+
|
|
18
|
+
// ========================================================================
|
|
19
|
+
// Constructors
|
|
20
|
+
// ========================================================================
|
|
21
|
+
|
|
22
|
+
public KHash() {
|
|
23
|
+
this.data = new LinkedHashMap<>();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public KHash(Map<? extends K, ? extends V> m) {
|
|
27
|
+
this.data = new LinkedHashMap<>(m);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ========================================================================
|
|
31
|
+
// Ruby-specific methods
|
|
32
|
+
// ========================================================================
|
|
33
|
+
|
|
34
|
+
/** Ruby: hash.deconstruct_keys(keys) — returns self (for pattern matching) */
|
|
35
|
+
@SuppressWarnings("unchecked")
|
|
36
|
+
public KHash<K, V> deconstruct_keys(Object keys) {
|
|
37
|
+
// In Ruby, deconstruct_keys returns a hash with only the specified keys.
|
|
38
|
+
// For simplicity, return self — the pattern matcher will check keys individually.
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Ruby: hash.length / hash.size — returns long (Ruby Integer) */
|
|
43
|
+
public long length() {
|
|
44
|
+
return data.size();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Ruby: hash.has_key?(key) / hash.key?(key) */
|
|
48
|
+
public boolean hasKey(K key) {
|
|
49
|
+
return data.containsKey(key);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Ruby: hash.has_value?(value) / hash.value?(value) */
|
|
53
|
+
public boolean hasValue(V value) {
|
|
54
|
+
return data.containsValue(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Ruby: hash.keys — returns KArray */
|
|
58
|
+
public KArray<K> rubyKeys() {
|
|
59
|
+
return new KArray<>(data.keySet());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Ruby: hash.values — returns KArray */
|
|
63
|
+
public KArray<V> rubyValues() {
|
|
64
|
+
return new KArray<>(data.values());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Ruby: hash.empty? */
|
|
68
|
+
public boolean isEmpty_() {
|
|
69
|
+
return data.isEmpty();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Ruby: hash.fetch(key, default) */
|
|
73
|
+
public V fetch(K key, V defaultValue) {
|
|
74
|
+
V value = data.get(key);
|
|
75
|
+
return value != null ? value : defaultValue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Ruby: hash.merge(other) — returns new hash */
|
|
79
|
+
public KHash<K, V> merge(KHash<K, V> other) {
|
|
80
|
+
KHash<K, V> result = new KHash<>(this.data);
|
|
81
|
+
result.data.putAll(other.data);
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Ruby: hash.to_a — returns array of [key, value] pairs */
|
|
86
|
+
public KArray<KArray<Object>> toArray_() {
|
|
87
|
+
KArray<KArray<Object>> result = new KArray<>();
|
|
88
|
+
for (Map.Entry<K, V> entry : data.entrySet()) {
|
|
89
|
+
KArray<Object> pair = new KArray<>(2);
|
|
90
|
+
pair.add(entry.getKey());
|
|
91
|
+
pair.add(entry.getValue());
|
|
92
|
+
result.add(pair);
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Ruby: hash.count (without block) */
|
|
98
|
+
public long count() {
|
|
99
|
+
return data.size();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Ruby: hash.merge!(other) / hash.update(other) — mutating merge */
|
|
103
|
+
@SuppressWarnings("unchecked")
|
|
104
|
+
public KHash<K, V> mergeInPlace(KHash<K, V> other) {
|
|
105
|
+
this.data.putAll(other.data);
|
|
106
|
+
return this;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Ruby: hash.each_key { |k| ... } support — returns keys as KArray */
|
|
110
|
+
public KArray<K> eachKeys() {
|
|
111
|
+
return new KArray<>(data.keySet());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Ruby: hash.each_value { |v| ... } support — returns values as KArray */
|
|
115
|
+
public KArray<V> eachValues() {
|
|
116
|
+
return new KArray<>(data.values());
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ========================================================================
|
|
120
|
+
// Map<K,V> interface delegation
|
|
121
|
+
// ========================================================================
|
|
122
|
+
|
|
123
|
+
@Override
|
|
124
|
+
public int size() {
|
|
125
|
+
return data.size();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
@Override
|
|
129
|
+
public boolean isEmpty() {
|
|
130
|
+
return data.isEmpty();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@Override
|
|
134
|
+
public boolean containsKey(Object key) {
|
|
135
|
+
return data.containsKey(key);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@Override
|
|
139
|
+
public boolean containsValue(Object value) {
|
|
140
|
+
return data.containsValue(value);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@Override
|
|
144
|
+
public V get(Object key) {
|
|
145
|
+
return data.get(key);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@Override
|
|
149
|
+
public V put(K key, V value) {
|
|
150
|
+
return data.put(key, value);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@Override
|
|
154
|
+
public V remove(Object key) {
|
|
155
|
+
return data.remove(key);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@Override
|
|
159
|
+
public void putAll(Map<? extends K, ? extends V> m) {
|
|
160
|
+
data.putAll(m);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@Override
|
|
164
|
+
public void clear() {
|
|
165
|
+
data.clear();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
@Override
|
|
169
|
+
public Set<K> keySet() {
|
|
170
|
+
return data.keySet();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@Override
|
|
174
|
+
public Collection<V> values() {
|
|
175
|
+
return data.values();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@Override
|
|
179
|
+
public Set<Map.Entry<K, V>> entrySet() {
|
|
180
|
+
return data.entrySet();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ========================================================================
|
|
184
|
+
// Ruby-compatible toString: {"a" => 1, "b" => 2}
|
|
185
|
+
// ========================================================================
|
|
186
|
+
|
|
187
|
+
@Override
|
|
188
|
+
public String toString() {
|
|
189
|
+
StringBuilder sb = new StringBuilder("{");
|
|
190
|
+
boolean first = true;
|
|
191
|
+
for (Map.Entry<K, V> entry : data.entrySet()) {
|
|
192
|
+
if (!first) sb.append(", ");
|
|
193
|
+
first = false;
|
|
194
|
+
K key = entry.getKey();
|
|
195
|
+
V value = entry.getValue();
|
|
196
|
+
if (key instanceof String) {
|
|
197
|
+
sb.append("\"").append(key).append("\"");
|
|
198
|
+
} else {
|
|
199
|
+
sb.append(key);
|
|
200
|
+
}
|
|
201
|
+
sb.append(" => ");
|
|
202
|
+
if (value instanceof String) {
|
|
203
|
+
sb.append("\"").append(value).append("\"");
|
|
204
|
+
} else {
|
|
205
|
+
sb.append(value);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
sb.append("}");
|
|
209
|
+
return sb.toString();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
@Override
|
|
213
|
+
public boolean equals(Object o) {
|
|
214
|
+
if (this == o) return true;
|
|
215
|
+
if (o instanceof KHash) {
|
|
216
|
+
return data.equals(((KHash<?, ?>) o).data);
|
|
217
|
+
}
|
|
218
|
+
if (o instanceof Map) {
|
|
219
|
+
return data.equals(o);
|
|
220
|
+
}
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
@Override
|
|
225
|
+
public int hashCode() {
|
|
226
|
+
return data.hashCode();
|
|
227
|
+
}
|
|
228
|
+
}
|