freelang-v4 4.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.
Files changed (261) hide show
  1. package/README.md +548 -0
  2. package/dist/ast.d.ts +367 -0
  3. package/dist/ast.js +4 -0
  4. package/dist/ast.js.map +1 -0
  5. package/dist/async-basic.test.d.ts +1 -0
  6. package/dist/async-basic.test.js +88 -0
  7. package/dist/async-basic.test.js.map +1 -0
  8. package/dist/async-jest.test.d.ts +1 -0
  9. package/dist/async-jest.test.js +99 -0
  10. package/dist/async-jest.test.js.map +1 -0
  11. package/dist/channel-jest.test.d.ts +1 -0
  12. package/dist/channel-jest.test.js +148 -0
  13. package/dist/channel-jest.test.js.map +1 -0
  14. package/dist/checker-jest.test.d.ts +1 -0
  15. package/dist/checker-jest.test.js +160 -0
  16. package/dist/checker-jest.test.js.map +1 -0
  17. package/dist/checker.d.ts +149 -0
  18. package/dist/checker.js +1565 -0
  19. package/dist/checker.js.map +1 -0
  20. package/dist/checker.test.d.ts +1 -0
  21. package/dist/checker.test.js +217 -0
  22. package/dist/checker.test.js.map +1 -0
  23. package/dist/compiler-jest.test.d.ts +1 -0
  24. package/dist/compiler-jest.test.js +233 -0
  25. package/dist/compiler-jest.test.js.map +1 -0
  26. package/dist/compiler.d.ts +127 -0
  27. package/dist/compiler.js +1588 -0
  28. package/dist/compiler.js.map +1 -0
  29. package/dist/compiler.test.d.ts +1 -0
  30. package/dist/compiler.test.js +313 -0
  31. package/dist/compiler.test.js.map +1 -0
  32. package/dist/db-100m-full.d.ts +5 -0
  33. package/dist/db-100m-full.js +78 -0
  34. package/dist/db-100m-full.js.map +1 -0
  35. package/dist/db-100m-no-index.d.ts +12 -0
  36. package/dist/db-100m-no-index.js +119 -0
  37. package/dist/db-100m-no-index.js.map +1 -0
  38. package/dist/db-100m-real.d.ts +5 -0
  39. package/dist/db-100m-real.js +131 -0
  40. package/dist/db-100m-real.js.map +1 -0
  41. package/dist/db-100m-streaming.d.ts +15 -0
  42. package/dist/db-100m-streaming.js +164 -0
  43. package/dist/db-100m-streaming.js.map +1 -0
  44. package/dist/db-100m-test.d.ts +5 -0
  45. package/dist/db-100m-test.js +111 -0
  46. package/dist/db-100m-test.js.map +1 -0
  47. package/dist/db-jest.test.d.ts +1 -0
  48. package/dist/db-jest.test.js +182 -0
  49. package/dist/db-jest.test.js.map +1 -0
  50. package/dist/db-runtime.d.ts +24 -0
  51. package/dist/db-runtime.js +204 -0
  52. package/dist/db-runtime.js.map +1 -0
  53. package/dist/db.d.ts +249 -0
  54. package/dist/db.js +593 -0
  55. package/dist/db.js.map +1 -0
  56. package/dist/file-io-jest.test.d.ts +1 -0
  57. package/dist/file-io-jest.test.js +225 -0
  58. package/dist/file-io-jest.test.js.map +1 -0
  59. package/dist/for-of-jest.test.d.ts +1 -0
  60. package/dist/for-of-jest.test.js +230 -0
  61. package/dist/for-of-jest.test.js.map +1 -0
  62. package/dist/for-of.test.d.ts +1 -0
  63. package/dist/for-of.test.js +305 -0
  64. package/dist/for-of.test.js.map +1 -0
  65. package/dist/function-literal-jest.test.d.ts +1 -0
  66. package/dist/function-literal-jest.test.js +180 -0
  67. package/dist/function-literal-jest.test.js.map +1 -0
  68. package/dist/function-literal.test.d.ts +1 -0
  69. package/dist/function-literal.test.js +245 -0
  70. package/dist/function-literal.test.js.map +1 -0
  71. package/dist/generics-jest.test.d.ts +1 -0
  72. package/dist/generics-jest.test.js +93 -0
  73. package/dist/generics-jest.test.js.map +1 -0
  74. package/dist/ir-gen.d.ts +15 -0
  75. package/dist/ir-gen.js +400 -0
  76. package/dist/ir-gen.js.map +1 -0
  77. package/dist/ir.d.ts +114 -0
  78. package/dist/ir.js +5 -0
  79. package/dist/ir.js.map +1 -0
  80. package/dist/lexer.d.ts +110 -0
  81. package/dist/lexer.js +467 -0
  82. package/dist/lexer.js.map +1 -0
  83. package/dist/lexer.test.d.ts +1 -0
  84. package/dist/lexer.test.js +426 -0
  85. package/dist/lexer.test.js.map +1 -0
  86. package/dist/main.d.ts +2 -0
  87. package/dist/main.js +241 -0
  88. package/dist/main.js.map +1 -0
  89. package/dist/module-jest.test.d.ts +1 -0
  90. package/dist/module-jest.test.js +123 -0
  91. package/dist/module-jest.test.js.map +1 -0
  92. package/dist/parser.d.ts +56 -0
  93. package/dist/parser.js +1060 -0
  94. package/dist/parser.js.map +1 -0
  95. package/dist/parser.test.d.ts +1 -0
  96. package/dist/parser.test.js +461 -0
  97. package/dist/parser.test.js.map +1 -0
  98. package/dist/pattern-matching-jest.test.d.ts +1 -0
  99. package/dist/pattern-matching-jest.test.js +158 -0
  100. package/dist/pattern-matching-jest.test.js.map +1 -0
  101. package/dist/pkg/init.d.ts +1 -0
  102. package/dist/pkg/init.js +118 -0
  103. package/dist/pkg/init.js.map +1 -0
  104. package/dist/pkg/install.d.ts +1 -0
  105. package/dist/pkg/install.js +77 -0
  106. package/dist/pkg/install.js.map +1 -0
  107. package/dist/pkg/registry.d.ts +23 -0
  108. package/dist/pkg/registry.js +106 -0
  109. package/dist/pkg/registry.js.map +1 -0
  110. package/dist/pkg/run.d.ts +1 -0
  111. package/dist/pkg/run.js +76 -0
  112. package/dist/pkg/run.js.map +1 -0
  113. package/dist/pkg/toml.d.ts +5 -0
  114. package/dist/pkg/toml.js +117 -0
  115. package/dist/pkg/toml.js.map +1 -0
  116. package/dist/repl.d.ts +15 -0
  117. package/dist/repl.js +197 -0
  118. package/dist/repl.js.map +1 -0
  119. package/dist/runtime/bytecode.d.ts +92 -0
  120. package/dist/runtime/bytecode.js +253 -0
  121. package/dist/runtime/bytecode.js.map +1 -0
  122. package/dist/runtime/value.d.ts +102 -0
  123. package/dist/runtime/value.js +302 -0
  124. package/dist/runtime/value.js.map +1 -0
  125. package/dist/runtime/vm.d.ts +65 -0
  126. package/dist/runtime/vm.js +293 -0
  127. package/dist/runtime/vm.js.map +1 -0
  128. package/dist/struct-instance-jest.test.d.ts +1 -0
  129. package/dist/struct-instance-jest.test.js +209 -0
  130. package/dist/struct-instance-jest.test.js.map +1 -0
  131. package/dist/struct-instance.test.d.ts +1 -0
  132. package/dist/struct-instance.test.js +291 -0
  133. package/dist/struct-instance.test.js.map +1 -0
  134. package/dist/struct-jest.test.d.ts +1 -0
  135. package/dist/struct-jest.test.js +176 -0
  136. package/dist/struct-jest.test.js.map +1 -0
  137. package/dist/struct.test.d.ts +1 -0
  138. package/dist/struct.test.js +231 -0
  139. package/dist/struct.test.js.map +1 -0
  140. package/dist/trait-jest.test.d.ts +1 -0
  141. package/dist/trait-jest.test.js +120 -0
  142. package/dist/trait-jest.test.js.map +1 -0
  143. package/dist/vm-jest.test.d.ts +1 -0
  144. package/dist/vm-jest.test.js +569 -0
  145. package/dist/vm-jest.test.js.map +1 -0
  146. package/dist/vm.d.ts +81 -0
  147. package/dist/vm.js +1956 -0
  148. package/dist/vm.js.map +1 -0
  149. package/dist/vm.test.d.ts +1 -0
  150. package/dist/vm.test.js +337 -0
  151. package/dist/vm.test.js.map +1 -0
  152. package/dist/web-repl/sandbox.d.ts +11 -0
  153. package/dist/web-repl/sandbox.js +76 -0
  154. package/dist/web-repl/sandbox.js.map +1 -0
  155. package/dist/web-repl/server.d.ts +1 -0
  156. package/dist/web-repl/server.js +111 -0
  157. package/dist/web-repl/server.js.map +1 -0
  158. package/dist/while-loop-jest.test.d.ts +1 -0
  159. package/dist/while-loop-jest.test.js +201 -0
  160. package/dist/while-loop-jest.test.js.map +1 -0
  161. package/dist/while-loop.test.d.ts +1 -0
  162. package/dist/while-loop.test.js +262 -0
  163. package/dist/while-loop.test.js.map +1 -0
  164. package/docs/EXPERIENCE.md +787 -0
  165. package/docs/README.md +175 -0
  166. package/docs/V1_V2_V3_ANALYSIS.md +107 -0
  167. package/docs/_config.yml +36 -0
  168. package/docs/api-reference.md +459 -0
  169. package/docs/architecture.md +470 -0
  170. package/docs/benchmarks.md +295 -0
  171. package/docs/comparison.md +454 -0
  172. package/docs/index.md +335 -0
  173. package/docs/language-completeness.md +228 -0
  174. package/docs/learning-guide.md +651 -0
  175. package/package.json +65 -0
  176. package/src/api/deploy_key.fl +294 -0
  177. package/src/api/issue.fl +302 -0
  178. package/src/api/org.fl +356 -0
  179. package/src/api/repo.fl +394 -0
  180. package/src/api/team.fl +299 -0
  181. package/src/api/user.fl +385 -0
  182. package/src/api/webhook.fl +273 -0
  183. package/src/ast.ts +158 -0
  184. package/src/async-basic.test.ts +94 -0
  185. package/src/async-jest.test.ts +107 -0
  186. package/src/channel-jest.test.ts +158 -0
  187. package/src/checker-jest.test.ts +189 -0
  188. package/src/checker.test.ts +279 -0
  189. package/src/checker.ts +1861 -0
  190. package/src/commands/analyze.fl +227 -0
  191. package/src/commands/auth.fl +315 -0
  192. package/src/commands/batch.fl +349 -0
  193. package/src/commands/config.fl +199 -0
  194. package/src/commands/deploy_key.fl +352 -0
  195. package/src/commands/issue.fl +275 -0
  196. package/src/commands/main.fl +492 -0
  197. package/src/commands/org.fl +425 -0
  198. package/src/commands/repo.fl +581 -0
  199. package/src/commands/team.fl +244 -0
  200. package/src/commands/user.fl +423 -0
  201. package/src/commands/webhook.fl +400 -0
  202. package/src/compiler-jest.test.ts +275 -0
  203. package/src/compiler.test.ts +375 -0
  204. package/src/compiler.ts +1770 -0
  205. package/src/config.fl +175 -0
  206. package/src/core/batch.fl +355 -0
  207. package/src/core/cache.fl +284 -0
  208. package/src/core/ensure.fl +324 -0
  209. package/src/db-100m-full.ts +96 -0
  210. package/src/db-100m-no-index.ts +133 -0
  211. package/src/db-100m-real.ts +152 -0
  212. package/src/db-100m-streaming.ts +154 -0
  213. package/src/db-100m-test.ts +136 -0
  214. package/src/db-jest.test.ts +161 -0
  215. package/src/db-runtime.ts +242 -0
  216. package/src/db.ts +676 -0
  217. package/src/errors.fl +134 -0
  218. package/src/for-of-jest.test.ts +246 -0
  219. package/src/for-of.test.ts +308 -0
  220. package/src/function-literal-jest.test.ts +193 -0
  221. package/src/function-literal.test.ts +248 -0
  222. package/src/generics-jest.test.ts +104 -0
  223. package/src/http/client.fl +327 -0
  224. package/src/ir-gen.ts +459 -0
  225. package/src/ir.ts +80 -0
  226. package/src/lexer.test.ts +499 -0
  227. package/src/lexer.ts +522 -0
  228. package/src/main.ts +223 -0
  229. package/src/models.fl +162 -0
  230. package/src/module-jest.test.ts +145 -0
  231. package/src/parser.test.ts +542 -0
  232. package/src/parser.ts +1211 -0
  233. package/src/pattern-matching-jest.test.ts +170 -0
  234. package/src/pkg/init.ts +91 -0
  235. package/src/pkg/install.ts +56 -0
  236. package/src/pkg/registry.ts +103 -0
  237. package/src/pkg/run.ts +49 -0
  238. package/src/pkg/toml.ts +129 -0
  239. package/src/repl.ts +190 -0
  240. package/src/runtime/bytecode.ts +291 -0
  241. package/src/runtime/value.ts +322 -0
  242. package/src/runtime/vm.ts +354 -0
  243. package/src/self-host/bootstrap.fl +68 -0
  244. package/src/self-host/interpreter.fl +361 -0
  245. package/src/self-host/lexer-simple.fl +22 -0
  246. package/src/self-host/lexer.fl +305 -0
  247. package/src/self-host/parser.fl +580 -0
  248. package/src/struct-instance-jest.test.ts +221 -0
  249. package/src/struct-instance.test.ts +293 -0
  250. package/src/struct-jest.test.ts +187 -0
  251. package/src/struct.test.ts +234 -0
  252. package/src/trait-jest.test.ts +136 -0
  253. package/src/vm-jest.test.ts +754 -0
  254. package/src/vm.ts +1976 -0
  255. package/src/web-repl/public/index.html +50 -0
  256. package/src/web-repl/public/main.js +105 -0
  257. package/src/web-repl/public/style.css +225 -0
  258. package/src/web-repl/sandbox.ts +88 -0
  259. package/src/web-repl/server.ts +97 -0
  260. package/src/while-loop-jest.test.ts +218 -0
  261. package/src/while-loop.test.ts +267 -0
@@ -0,0 +1,400 @@
1
+ // FreeLang v4.2 — gogs-cli Phase 5 웹훅 명령어
2
+ // create, list, delete 구현
3
+ // 200라인
4
+
5
+ /// 웹훅 생성
6
+ /// gogs webhook create OWNER/REPO --url URL [--events "push,pull_request"]
7
+ async fn cmd_webhook_create(args: CliArgs) -> CliResult {
8
+ // 1. 인자 검증
9
+ var repo_path = get_positional(args, 0)
10
+ if repo_path == "" {
11
+ return CliResult {
12
+ exit_code: 1,
13
+ output: "",
14
+ error: "Repository path (OWNER/REPO) is required"
15
+ }
16
+ }
17
+
18
+ var parts = split_repo_path(repo_path)
19
+ if length(parts) != 2 {
20
+ return CliResult {
21
+ exit_code: 1,
22
+ output: "",
23
+ error: "Invalid repository path. Use: OWNER/REPO"
24
+ }
25
+ }
26
+
27
+ var owner = parts[0]
28
+ var repo_name = parts[1]
29
+
30
+ // 2. 플래그 파싱
31
+ var webhook_url = get_flag(args, "url")
32
+ if webhook_url == "" {
33
+ return CliResult {
34
+ exit_code: 1,
35
+ output: "",
36
+ error: "--url is required"
37
+ }
38
+ }
39
+
40
+ var events_str = get_flag(args, "events")
41
+ if events_str == "" {
42
+ events_str = "push"
43
+ }
44
+ var events = split_events(events_str)
45
+
46
+ // 3. 설정 로드
47
+ var host = await get_default_host()
48
+ if host.url == "" {
49
+ return CliResult {
50
+ exit_code: 1,
51
+ output: "",
52
+ error: "Not logged in"
53
+ }
54
+ }
55
+
56
+ // 4. 클라이언트 및 캐시
57
+ var client = new_client(host.url, host.token)
58
+ var cache = new_cache(300)
59
+
60
+ // 5. API 호출
61
+ println("Creating webhook for " + repo_path + "...")
62
+
63
+ var webhook_service = new_webhook_service(client, cache)
64
+ var req = CreateWebhookRequest {
65
+ url: webhook_url,
66
+ content_type: "json",
67
+ events: events,
68
+ active: true
69
+ }
70
+ var result = await create_webhook(webhook_service, owner, repo_name, req)
71
+
72
+ // 6. 결과 처리
73
+ match result {
74
+ Result::Ok(webhook) => {
75
+ var output = ""
76
+ output = output + "✓ Webhook created\n"
77
+ output = output + " ID: " + str(webhook.id) + "\n"
78
+ output = output + " URL: " + webhook.url + "\n"
79
+ output = output + " Active: " + bool_to_str(webhook.active) + "\n"
80
+
81
+ CliResult {
82
+ exit_code: 0,
83
+ output: output,
84
+ error: ""
85
+ }
86
+ }
87
+ Result::Err(err) => {
88
+ CliResult {
89
+ exit_code: 1,
90
+ output: "",
91
+ error: error_message(err)
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ /// 웹훅 목록
98
+ /// gogs webhook list OWNER/REPO [--json] [--yaml]
99
+ async fn cmd_webhook_list(args: CliArgs) -> CliResult {
100
+ // 1. 인자 검증
101
+ var repo_path = get_positional(args, 0)
102
+ if repo_path == "" {
103
+ return CliResult {
104
+ exit_code: 1,
105
+ output: "",
106
+ error: "Repository path (OWNER/REPO) is required"
107
+ }
108
+ }
109
+
110
+ var parts = split_repo_path(repo_path)
111
+ if length(parts) != 2 {
112
+ return CliResult {
113
+ exit_code: 1,
114
+ output: "",
115
+ error: "Invalid repository path. Use: OWNER/REPO"
116
+ }
117
+ }
118
+
119
+ var owner = parts[0]
120
+ var repo_name = parts[1]
121
+
122
+ // 2. 설정 로드
123
+ var host = await get_default_host()
124
+ if host.url == "" {
125
+ return CliResult {
126
+ exit_code: 1,
127
+ output: "",
128
+ error: "Not logged in"
129
+ }
130
+ }
131
+
132
+ // 3. 클라이언트 및 캐시
133
+ var client = new_client(host.url, host.token)
134
+ var cache = new_cache(300)
135
+
136
+ // 4. API 호출
137
+ println("Fetching webhooks for " + repo_path + "...")
138
+
139
+ var webhook_service = new_webhook_service(client, cache)
140
+ var result = await list_webhooks(webhook_service, owner, repo_name)
141
+
142
+ // 5. 결과 처리
143
+ match result {
144
+ Result::Ok(webhooks) => {
145
+ var format = get_format(args)
146
+
147
+ if format == "json" {
148
+ return webhook_list_json(webhooks)
149
+ }
150
+ if format == "yaml" {
151
+ return webhook_list_yaml(webhooks)
152
+ }
153
+
154
+ webhook_list_text(webhooks)
155
+ }
156
+ Result::Err(err) => {
157
+ CliResult {
158
+ exit_code: 1,
159
+ output: "",
160
+ error: error_message(err)
161
+ }
162
+ }
163
+ }
164
+ }
165
+
166
+ /// 웹훅 삭제
167
+ /// gogs webhook delete OWNER/REPO WEBHOOK_ID [--force]
168
+ async fn cmd_webhook_delete(args: CliArgs) -> CliResult {
169
+ // 1. 인자 검증
170
+ var repo_path = get_positional(args, 0)
171
+ var webhook_id_str = get_positional(args, 1)
172
+
173
+ if repo_path == "" || webhook_id_str == "" {
174
+ return CliResult {
175
+ exit_code: 1,
176
+ output: "",
177
+ error: "Repository path and webhook ID are required"
178
+ }
179
+ }
180
+
181
+ var parts = split_repo_path(repo_path)
182
+ if length(parts) != 2 {
183
+ return CliResult {
184
+ exit_code: 1,
185
+ output: "",
186
+ error: "Invalid repository path. Use: OWNER/REPO"
187
+ }
188
+ }
189
+
190
+ var owner = parts[0]
191
+ var repo_name = parts[1]
192
+
193
+ // 2. 플래그 확인
194
+ var force = has_flag(args, "force")
195
+ if !force {
196
+ println("⚠️ This will delete webhook " + webhook_id_str)
197
+ println("Run with --force to confirm")
198
+ return CliResult {
199
+ exit_code: 1,
200
+ output: "",
201
+ error: "Deletion not confirmed"
202
+ }
203
+ }
204
+
205
+ // 3. 설정 로드
206
+ var host = await get_default_host()
207
+ if host.url == "" {
208
+ return CliResult {
209
+ exit_code: 1,
210
+ output: "",
211
+ error: "Not logged in"
212
+ }
213
+ }
214
+
215
+ // 4. 클라이언트 및 캐시
216
+ var client = new_client(host.url, host.token)
217
+ var cache = new_cache(300)
218
+
219
+ // 5. API 호출
220
+ println("Deleting webhook " + webhook_id_str + "...")
221
+
222
+ var webhook_service = new_webhook_service(client, cache)
223
+ var result = await delete_webhook(webhook_service, owner, repo_name, parse_int(webhook_id_str))
224
+
225
+ // 6. 결과 처리
226
+ match result {
227
+ Result::Ok(_) => {
228
+ CliResult {
229
+ exit_code: 0,
230
+ output: "✓ Webhook deleted: " + webhook_id_str,
231
+ error: ""
232
+ }
233
+ }
234
+ Result::Err(err) => {
235
+ CliResult {
236
+ exit_code: 1,
237
+ output: "",
238
+ error: error_message(err)
239
+ }
240
+ }
241
+ }
242
+ }
243
+
244
+ // ==================== 출력 포맷 ====================
245
+
246
+ fn webhook_list_text(webhooks: [Webhook]) -> CliResult {
247
+ var output = ""
248
+ output = output + "╔════════════════════════════════════════════════════════════════════╗\n"
249
+ output = output + "║ Webhook List ║\n"
250
+ output = output + "╚════════════════════════════════════════════════════════════════════╝\n"
251
+ output = output + "\n"
252
+
253
+ if length(webhooks) == 0 {
254
+ output = output + "No webhooks found\n"
255
+ return CliResult {
256
+ exit_code: 0,
257
+ output: output,
258
+ error: ""
259
+ }
260
+ }
261
+
262
+ var i: i32 = 0
263
+ while i < length(webhooks) {
264
+ var webhook = webhooks[i]
265
+ var active_mark = if webhook.active then "✓" else "✗"
266
+ output = output + "[" + active_mark + "] " + str(webhook.id) + ": " + webhook.url + "\n"
267
+ output = output + " Events: " + events_to_str(webhook.events) + "\n"
268
+ output = output + "\n"
269
+ i = i + 1
270
+ }
271
+
272
+ output = output + "Total: " + str(length(webhooks)) + " webhooks\n"
273
+
274
+ CliResult {
275
+ exit_code: 0,
276
+ output: output,
277
+ error: ""
278
+ }
279
+ }
280
+
281
+ fn webhook_list_json(webhooks: [Webhook]) -> CliResult {
282
+ var json = "[\n"
283
+ var i: i32 = 0
284
+ while i < length(webhooks) {
285
+ var w = webhooks[i]
286
+ json = json + " {\"id\": " + str(w.id) + ", \"url\": \"" + w.url + "\", \"active\": " + bool_to_json(w.active) + "}"
287
+ if i < length(webhooks) - 1 { json = json + "," }
288
+ json = json + "\n"
289
+ i = i + 1
290
+ }
291
+ json = json + "]\n"
292
+ CliResult { exit_code: 0, output: json, error: "" }
293
+ }
294
+
295
+ fn webhook_list_yaml(webhooks: [Webhook]) -> CliResult {
296
+ var yaml = "webhooks:\n"
297
+ var i: i32 = 0
298
+ while i < length(webhooks) {
299
+ var w = webhooks[i]
300
+ yaml = yaml + " - id: " + str(w.id) + "\n"
301
+ yaml = yaml + " url: " + w.url + "\n"
302
+ yaml = yaml + " active: " + bool_to_str(w.active) + "\n"
303
+ i = i + 1
304
+ }
305
+ CliResult { exit_code: 0, output: yaml, error: "" }
306
+ }
307
+
308
+ // ==================== 유틸리티 ====================
309
+
310
+ fn split_repo_path(path: str) -> [str] {
311
+ var result: [str] = []
312
+ var idx = indexOf(path, "/")
313
+ if idx == -1 {
314
+ result.push(path)
315
+ return result
316
+ }
317
+ result.push(substring(path, 0, idx))
318
+ result.push(substring(path, idx + 1, length(path)))
319
+ result
320
+ }
321
+
322
+ fn split_events(events_str: str) -> [str] {
323
+ var result: [str] = []
324
+ var parts = split_by(events_str, ",")
325
+ var i: i32 = 0
326
+ while i < length(parts) {
327
+ var event = trim(parts[i])
328
+ if event != "" {
329
+ result.push(event)
330
+ }
331
+ i = i + 1
332
+ }
333
+ result
334
+ }
335
+
336
+ fn split_by(s: str, sep: str) -> [str] {
337
+ var result: [str] = []
338
+ var current = ""
339
+ var i: i32 = 0
340
+ while i < length(s) {
341
+ var ch = substring(s, i, i + 1)
342
+ if ch == sep {
343
+ result.push(current)
344
+ current = ""
345
+ } else {
346
+ current = current + ch
347
+ }
348
+ i = i + 1
349
+ }
350
+ if current != "" {
351
+ result.push(current)
352
+ }
353
+ result
354
+ }
355
+
356
+ fn trim(s: str) -> str {
357
+ s // TODO: implement trim
358
+ }
359
+
360
+ fn events_to_str(events: [str]) -> str {
361
+ var result = ""
362
+ var i: i32 = 0
363
+ while i < length(events) {
364
+ result = result + events[i]
365
+ if i < length(events) - 1 {
366
+ result = result + ", "
367
+ }
368
+ i = i + 1
369
+ }
370
+ result
371
+ }
372
+
373
+ fn indexOf(s: str, substr: str) -> i32 {
374
+ var i: i32 = 0
375
+ var len = length(s)
376
+ var sublen = length(substr)
377
+ while i <= len - sublen {
378
+ if substring(s, i, i + sublen) == substr { return i }
379
+ i = i + 1
380
+ }
381
+ -1
382
+ }
383
+
384
+ fn bool_to_str(b: bool) -> str {
385
+ if b { "true" } else { "false" }
386
+ }
387
+
388
+ fn bool_to_json(b: bool) -> str {
389
+ if b { "true" } else { "false" }
390
+ }
391
+
392
+ fn parse_int(s: str) -> i32 {
393
+ 0 // TODO: implement parse_int
394
+ }
395
+
396
+ // 필요한 함수들:
397
+ // - get_positional, has_flag, get_flag, get_format
398
+ // - get_default_host, new_client, new_cache
399
+ // - new_webhook_service, create_webhook, list_webhooks, delete_webhook
400
+ // - error_message
@@ -0,0 +1,275 @@
1
+ // FreeLang v4 — Compiler 테스트 - Jest Format
2
+
3
+ import { Lexer } from "./lexer";
4
+ import { Parser } from "./parser";
5
+ import { Compiler, Chunk, Op } from "./compiler";
6
+
7
+ function compile(source: string): Chunk {
8
+ const { tokens, errors: lexErrors } = new Lexer(source).tokenize();
9
+ if (lexErrors.length > 0) throw new Error(`Lex: ${lexErrors[0].message}`);
10
+ const { program, errors: parseErrors } = new Parser(tokens).parse();
11
+ if (parseErrors.length > 0) throw new Error(`Parse: ${parseErrors[0].message}`);
12
+ return new Compiler().compile(program);
13
+ }
14
+
15
+ function findOp(chunk: Chunk, op: Op): boolean {
16
+ return chunk.code.includes(op);
17
+ }
18
+
19
+ function countOp(chunk: Chunk, op: Op): number {
20
+ return chunk.code.filter((b) => b === op).length;
21
+ }
22
+
23
+ // ============================================================
24
+ // Jest Tests
25
+ // ============================================================
26
+
27
+ describe("Compiler Tests", () => {
28
+ describe("상수 로드", () => {
29
+ it("정수 리터럴", () => {
30
+ const c = compile("42");
31
+ expect(findOp(c, Op.PUSH_I32)).toBe(true);
32
+ expect(findOp(c, Op.HALT)).toBe(true);
33
+ });
34
+
35
+ it("부동소수점 리터럴", () => {
36
+ const c = compile("3.14");
37
+ expect(findOp(c, Op.PUSH_F64)).toBe(true);
38
+ });
39
+
40
+ it("문자열 리터럴", () => {
41
+ const c = compile('"hello"');
42
+ expect(findOp(c, Op.PUSH_STR)).toBe(true);
43
+ expect(c.constants.includes("hello")).toBe(true);
44
+ });
45
+
46
+ it("true 리터럴", () => {
47
+ const c = compile("true");
48
+ expect(findOp(c, Op.PUSH_TRUE)).toBe(true);
49
+ });
50
+
51
+ it("false 리터럴", () => {
52
+ const c = compile("false");
53
+ expect(findOp(c, Op.PUSH_FALSE)).toBe(true);
54
+ });
55
+ });
56
+
57
+ describe("산술 연산", () => {
58
+ it("1 + 2", () => {
59
+ const c = compile("1 + 2");
60
+ expect(findOp(c, Op.ADD_I32)).toBe(true);
61
+ });
62
+
63
+ it("3 - 1", () => {
64
+ const c = compile("3 - 1");
65
+ expect(findOp(c, Op.SUB_I32)).toBe(true);
66
+ });
67
+
68
+ it("2 * 3", () => {
69
+ const c = compile("2 * 3");
70
+ expect(findOp(c, Op.MUL_I32)).toBe(true);
71
+ });
72
+
73
+ it("6 / 2", () => {
74
+ const c = compile("6 / 2");
75
+ expect(findOp(c, Op.DIV_I32)).toBe(true);
76
+ });
77
+
78
+ it("7 % 3", () => {
79
+ const c = compile("7 % 3");
80
+ expect(findOp(c, Op.MOD_I32)).toBe(true);
81
+ });
82
+ });
83
+
84
+ describe("비교 + 논리", () => {
85
+ it("==", () => {
86
+ const c = compile("1 == 2");
87
+ expect(findOp(c, Op.EQ)).toBe(true);
88
+ });
89
+
90
+ it("!=", () => {
91
+ const c = compile("1 != 2");
92
+ expect(findOp(c, Op.NEQ)).toBe(true);
93
+ });
94
+
95
+ it("<", () => {
96
+ const c = compile("1 < 2");
97
+ expect(findOp(c, Op.LT)).toBe(true);
98
+ });
99
+
100
+ it("&&", () => {
101
+ const c = compile("true && false");
102
+ expect(findOp(c, Op.AND)).toBe(true);
103
+ });
104
+
105
+ it("||", () => {
106
+ const c = compile("true || false");
107
+ expect(findOp(c, Op.OR)).toBe(true);
108
+ });
109
+ });
110
+
111
+ describe("단항 연산", () => {
112
+ it("-42", () => {
113
+ const c = compile("-42");
114
+ expect(findOp(c, Op.NEG_I32)).toBe(true);
115
+ });
116
+
117
+ it("!true", () => {
118
+ const c = compile("!true");
119
+ expect(findOp(c, Op.NOT)).toBe(true);
120
+ });
121
+ });
122
+
123
+ describe("변수", () => {
124
+ it("var x = 42", () => {
125
+ const c = compile("var x = 42");
126
+ expect(findOp(c, Op.STORE_LOCAL)).toBe(true);
127
+ });
128
+
129
+ it("var x = 42; x + 1", () => {
130
+ const c = compile("var x = 42\nx + 1");
131
+ expect(findOp(c, Op.STORE_LOCAL)).toBe(true);
132
+ expect(findOp(c, Op.LOAD_LOCAL)).toBe(true);
133
+ expect(findOp(c, Op.ADD_I32)).toBe(true);
134
+ });
135
+ });
136
+
137
+ describe("함수 호출", () => {
138
+ it("println은 builtin 함수", () => {
139
+ const c = compile('println("hello")');
140
+ const hasCall = findOp(c, Op.CALL_BUILTIN) || findOp(c, Op.CALL);
141
+ expect(hasCall).toBe(true);
142
+ });
143
+ });
144
+
145
+ describe("제어흐름", () => {
146
+ it("if 문", () => {
147
+ const c = compile("if true { var x = 1 }");
148
+ expect(findOp(c, Op.JUMP_IF_FALSE)).toBe(true);
149
+ });
150
+
151
+ it("while 문", () => {
152
+ const c = compile("while true { var x = 1 }");
153
+ expect(findOp(c, Op.JUMP)).toBe(true);
154
+ });
155
+ });
156
+
157
+ describe("배열", () => {
158
+ it("배열 리터럴", () => {
159
+ const c = compile("[1, 2, 3]");
160
+ expect(findOp(c, Op.ARRAY_NEW)).toBe(true);
161
+ });
162
+
163
+ it("배열 인덱싱", () => {
164
+ const c = compile("var arr = [1, 2, 3]\narr[0]");
165
+ expect(findOp(c, Op.ARRAY_GET)).toBe(true);
166
+ });
167
+
168
+ it("배열 요소 수정", () => {
169
+ const c = compile("var arr = [1, 2, 3]\narr[0] = 99");
170
+ expect(findOp(c, Op.ARRAY_SET)).toBe(true);
171
+ });
172
+ });
173
+
174
+ describe("리터럴 타입", () => {
175
+ it("f64 리터럴", () => {
176
+ const c = compile("3.14");
177
+ expect(findOp(c, Op.PUSH_F64)).toBe(true);
178
+ });
179
+ });
180
+
181
+ describe("구조체", () => {
182
+ it("구조체 생성", () => {
183
+ const c = compile("struct Point { x: i32 }\nvar p = Point { x: 10 }");
184
+ expect(findOp(c, Op.STRUCT_NEW)).toBe(true);
185
+ });
186
+
187
+ it("구조체 필드 접근", () => {
188
+ const c = compile("struct Point { x: i32 }\nvar p = Point { x: 10 }\np.x");
189
+ expect(findOp(c, Op.STRUCT_GET)).toBe(true);
190
+ });
191
+ });
192
+
193
+ describe("함수 정의 & 호출", () => {
194
+ it("함수 정의", () => {
195
+ const c = compile("fn add(a: i32, b: i32) -> i32 { a + b }");
196
+ expect(findOp(c, Op.CALL) || findOp(c, Op.CALL_BUILTIN) || findOp(c, Op.PUSH_I32)).toBe(true);
197
+ });
198
+
199
+ it("함수 호출", () => {
200
+ const c = compile("fn add(a: i32, b: i32) -> i32 { a + b }\nadd(1, 2)");
201
+ expect(findOp(c, Op.CALL)).toBe(true);
202
+ });
203
+
204
+ it("반환값", () => {
205
+ const c = compile("fn getNum() -> i32 { return 42 }");
206
+ expect(findOp(c, Op.RETURN)).toBe(true);
207
+ });
208
+ });
209
+
210
+ describe("변수 스코핑", () => {
211
+ it("로컬 변수 스토어", () => {
212
+ const c = compile("var x = 100");
213
+ expect(findOp(c, Op.STORE_LOCAL)).toBe(true);
214
+ });
215
+ });
216
+
217
+ describe("제어흐름 확장", () => {
218
+ it("if-else", () => {
219
+ const c = compile("if true { 1 } else { 2 }");
220
+ expect(findOp(c, Op.JUMP_IF_FALSE)).toBe(true);
221
+ expect(findOp(c, Op.JUMP)).toBe(true);
222
+ });
223
+
224
+ it("break 문", () => {
225
+ const c = compile("while true { break }");
226
+ expect(findOp(c, Op.JUMP)).toBe(true);
227
+ });
228
+
229
+ it("continue 문", () => {
230
+ const c = compile("while true { continue }");
231
+ expect(findOp(c, Op.JUMP)).toBe(true);
232
+ });
233
+
234
+ it("for...in 루프", () => {
235
+ const c = compile("for x in [1, 2] { var y = x }");
236
+ expect(findOp(c, Op.ARRAY_GET) || findOp(c, Op.JUMP)).toBe(true);
237
+ });
238
+ });
239
+
240
+ describe("비교 연산자 확장", () => {
241
+ it(">", () => {
242
+ const c = compile("1 > 2");
243
+ expect(findOp(c, Op.GT)).toBe(true);
244
+ });
245
+
246
+ it("<=", () => {
247
+ const c = compile("1 <= 2");
248
+ expect(findOp(c, Op.LTEQ)).toBe(true);
249
+ });
250
+
251
+ it(">=", () => {
252
+ const c = compile("1 >= 2");
253
+ expect(findOp(c, Op.GTEQ)).toBe(true);
254
+ });
255
+ });
256
+
257
+ describe("복잡한 표현식", () => {
258
+ it("연산자 우선순위", () => {
259
+ const c = compile("2 + 3 * 4");
260
+ expect(findOp(c, Op.MUL_I32)).toBe(true);
261
+ expect(findOp(c, Op.ADD_I32)).toBe(true);
262
+ expect(countOp(c, Op.PUSH_I32)).toBeGreaterThanOrEqual(3);
263
+ });
264
+
265
+ it("중첩 함수 호출", () => {
266
+ const c = compile('println(str(42))');
267
+ expect(findOp(c, Op.CALL_BUILTIN) || findOp(c, Op.CALL)).toBe(true);
268
+ });
269
+
270
+ it("배열 요소 함수 호출", () => {
271
+ const c = compile('var arr = [1, 2, 3]\nlength(arr)');
272
+ expect(findOp(c, Op.ARRAY_GET) || findOp(c, Op.CALL_BUILTIN)).toBe(true);
273
+ });
274
+ });
275
+ });