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,327 @@
1
+ // FreeLang v4.2 — Gogs HTTP 클라이언트
2
+ // REST API 통신의 기본 계층
3
+
4
+ /// HTTP 클라이언트
5
+ struct HttpClient {
6
+ base_url: str
7
+ token: str
8
+ timeout: i32 // 초 단위 (기본 30)
9
+ }
10
+
11
+ /// HTTP 응답 (파싱되지 않음)
12
+ struct HttpResponse {
13
+ status: i32
14
+ body: str
15
+ headers: [HttpHeader]
16
+ }
17
+
18
+ /// HTTP 헤더
19
+ struct HttpHeader {
20
+ name: str
21
+ value: str
22
+ }
23
+
24
+ /// HTTP 클라이언트 생성
25
+ fn new_client(base_url: str, token: str) -> HttpClient {
26
+ HttpClient {
27
+ base_url: base_url,
28
+ token: token,
29
+ timeout: 30
30
+ }
31
+ }
32
+
33
+ /// 기본 요청 헤더 생성
34
+ fn default_headers(token: str) -> [HttpHeader] {
35
+ var headers: [HttpHeader] = []
36
+
37
+ var ct = HttpHeader {
38
+ name: "Content-Type",
39
+ value: "application/json"
40
+ }
41
+ headers.push(ct)
42
+
43
+ if token != "" {
44
+ var auth = HttpHeader {
45
+ name: "Authorization",
46
+ value: "token " + token
47
+ }
48
+ headers.push(auth)
49
+ }
50
+
51
+ headers
52
+ }
53
+
54
+ /// 헤더 맵으로 변환 (fetch용)
55
+ fn headers_to_object(headers: [HttpHeader]) -> {str: str} {
56
+ var obj: {str: str} = {}
57
+ var i: i32 = 0
58
+ while i < length(headers) {
59
+ obj[headers[i].name] = headers[i].value
60
+ i = i + 1
61
+ }
62
+ obj
63
+ }
64
+
65
+ /// URL 빌드
66
+ fn build_url(base: str, path: str) -> str {
67
+ // base가 /로 끝나면 제거
68
+ var clean_base = base
69
+ if endsWith(base, "/") {
70
+ clean_base = substring(base, 0, length(base) - 1)
71
+ }
72
+
73
+ // path가 /로 시작하지 않으면 추가
74
+ var clean_path = path
75
+ if !startsWith(path, "/") {
76
+ clean_path = "/" + path
77
+ }
78
+
79
+ clean_base + clean_path
80
+ }
81
+
82
+ // ==================== GET 요청 ====================
83
+
84
+ /// GET 요청 (비동기)
85
+ async fn http_get(client: HttpClient, path: str) -> HttpResponse {
86
+ var url = build_url(client.base_url, path)
87
+ var headers = default_headers(client.token)
88
+ var headers_obj = headers_to_object(headers)
89
+
90
+ // fetch 호출
91
+ var resp = await fetch(url, "GET", headers_obj, null)
92
+
93
+ // 응답 파싱
94
+ return HttpResponse {
95
+ status: 200, // TODO: 실제 상태 코드 추출
96
+ body: resp,
97
+ headers: []
98
+ }
99
+ }
100
+
101
+ /// GET 요청 (기존 fetch 래퍼)
102
+ async fn get_request(url: str, token: str) -> str {
103
+ var headers: {str: str} = {}
104
+ headers["Content-Type"] = "application/json"
105
+ if token != "" {
106
+ headers["Authorization"] = "token " + token
107
+ }
108
+
109
+ await http_get_internal(url, headers)
110
+ }
111
+
112
+ // ==================== POST 요청 ====================
113
+
114
+ /// POST 요청 (JSON 데이터)
115
+ async fn http_post_json(client: HttpClient, path: str, data: str) -> HttpResponse {
116
+ var url = build_url(client.base_url, path)
117
+ var headers = default_headers(client.token)
118
+ var headers_obj = headers_to_object(headers)
119
+
120
+ // fetch 호출
121
+ var resp = await fetch(url, "POST", headers_obj, data)
122
+
123
+ return HttpResponse {
124
+ status: 201, // TODO: 실제 상태 코드 추출
125
+ body: resp,
126
+ headers: []
127
+ }
128
+ }
129
+
130
+ /// POST 요청 (Object → JSON 변환)
131
+ async fn http_post<T>(client: HttpClient, path: str, body: T) -> HttpResponse {
132
+ var json = json_stringify(body)
133
+ await http_post_json(client, path, json)
134
+ }
135
+
136
+ // ==================== PUT 요청 ====================
137
+
138
+ /// PUT 요청 (전체 업데이트)
139
+ async fn http_put<T>(client: HttpClient, path: str, body: T) -> HttpResponse {
140
+ var url = build_url(client.base_url, path)
141
+ var json = json_stringify(body)
142
+ var headers = default_headers(client.token)
143
+ var headers_obj = headers_to_object(headers)
144
+
145
+ var resp = await fetch(url, "PUT", headers_obj, json)
146
+
147
+ return HttpResponse {
148
+ status: 200,
149
+ body: resp,
150
+ headers: []
151
+ }
152
+ }
153
+
154
+ // ==================== DELETE 요청 ====================
155
+
156
+ /// DELETE 요청
157
+ async fn http_delete(client: HttpClient, path: str) -> HttpResponse {
158
+ var url = build_url(client.base_url, path)
159
+ var headers = default_headers(client.token)
160
+ var headers_obj = headers_to_object(headers)
161
+
162
+ var resp = await fetch(url, "DELETE", headers_obj, null)
163
+
164
+ return HttpResponse {
165
+ status: 204,
166
+ body: resp,
167
+ headers: []
168
+ }
169
+ }
170
+
171
+ // ==================== PATCH 요청 ====================
172
+
173
+ /// PATCH 요청 (부분 업데이트)
174
+ async fn http_patch<T>(client: HttpClient, path: str, body: T) -> HttpResponse {
175
+ var url = build_url(client.base_url, path)
176
+ var json = json_stringify(body)
177
+ var headers = default_headers(client.token)
178
+ var headers_obj = headers_to_object(headers)
179
+
180
+ var resp = await fetch(url, "PATCH", headers_obj, json)
181
+
182
+ return HttpResponse {
183
+ status: 200,
184
+ body: resp,
185
+ headers: []
186
+ }
187
+ }
188
+
189
+ // ==================== 응답 처리 ====================
190
+
191
+ /// 응답을 JSON으로 파싱
192
+ fn parse_response<T>(resp: HttpResponse) -> T {
193
+ // JSON 파싱
194
+ var obj = json_parse(resp.body)
195
+ obj as T
196
+ }
197
+
198
+ /// 응답 성공 확인
199
+ fn is_success(status: i32) -> bool {
200
+ status >= 200 && status < 300
201
+ }
202
+
203
+ /// 응답 에러 여부
204
+ fn is_error(status: i32) -> bool {
205
+ status >= 400
206
+ }
207
+
208
+ // ==================== 에러 처리 ====================
209
+
210
+ /// 응답에서 에러 생성
211
+ fn response_to_error(resp: HttpResponse) -> Error {
212
+ if resp.status == 404 {
213
+ return Error::NotFound(resp.body)
214
+ }
215
+ if resp.status == 400 {
216
+ return Error::BadRequest(resp.body)
217
+ }
218
+ if resp.status == 401 {
219
+ return Error::Unauthorized(resp.body)
220
+ }
221
+ if resp.status == 403 {
222
+ return Error::Forbidden(resp.body)
223
+ }
224
+ if resp.status >= 500 {
225
+ return Error::ServerError(resp.body)
226
+ }
227
+ if resp.status >= 400 {
228
+ return Error::HttpError(resp.status, resp.body)
229
+ }
230
+ Error::Unknown(resp.body)
231
+ }
232
+
233
+ // ==================== 높은 수준의 API ====================
234
+
235
+ /// 저장소 목록 조회
236
+ async fn list_repos(client: HttpClient) -> Result<[str]> {
237
+ var resp = await http_get(client, "/api/v1/user/repos")
238
+
239
+ if is_error(resp.status) {
240
+ return Result::Err(response_to_error(resp))
241
+ }
242
+
243
+ // TODO: 실제 Repo 구조체로 파싱
244
+ Result::Ok([])
245
+ }
246
+
247
+ /// 저장소 조회
248
+ async fn get_repo(client: HttpClient, owner: str, repo: str) -> Result<str> {
249
+ var path = "/api/v1/repos/" + owner + "/" + repo
250
+ var resp = await http_get(client, path)
251
+
252
+ if is_error(resp.status) {
253
+ return Result::Err(response_to_error(resp))
254
+ }
255
+
256
+ Result::Ok(resp.body)
257
+ }
258
+
259
+ /// 저장소 생성
260
+ async fn create_repo(client: HttpClient, name: str, private: bool, description: str) -> Result<str> {
261
+ var body = "{\"name\": \"" + name + "\", \"private\": " + str(private) + ", \"description\": \"" + description + "\"}"
262
+ var resp = await http_post_json(client, "/api/v1/user/repos", body)
263
+
264
+ if is_error(resp.status) {
265
+ return Result::Err(response_to_error(resp))
266
+ }
267
+
268
+ Result::Ok(resp.body)
269
+ }
270
+
271
+ /// 저장소 삭제
272
+ async fn delete_repo(client: HttpClient, owner: str, repo: str) -> Result<str> {
273
+ var path = "/api/v1/repos/" + owner + "/" + repo
274
+ var resp = await http_delete(client, path)
275
+
276
+ if is_error(resp.status) {
277
+ return Result::Err(response_to_error(resp))
278
+ }
279
+
280
+ Result::Ok("")
281
+ }
282
+
283
+ // ==================== 헬퍼 함수 ====================
284
+
285
+ fn startsWith(s: str, prefix: str) -> bool {
286
+ var i: i32 = 0
287
+ while i < length(prefix) {
288
+ if char_at(s, i) != char_at(prefix, i) {
289
+ return false
290
+ }
291
+ i = i + 1
292
+ }
293
+ true
294
+ }
295
+
296
+ fn endsWith(s: str, suffix: str) -> bool {
297
+ var s_len = length(s)
298
+ var suffix_len = length(suffix)
299
+ if suffix_len > s_len { return false }
300
+
301
+ var i: i32 = 0
302
+ while i < suffix_len {
303
+ if char_at(s, s_len - suffix_len + i) != char_at(suffix, i) {
304
+ return false
305
+ }
306
+ i = i + 1
307
+ }
308
+ true
309
+ }
310
+
311
+ fn substring(s: str, from: i32, to: i32) -> str {
312
+ var result = ""
313
+ var i: i32 = from
314
+ while i < to && i < length(s) {
315
+ result = result + char_at(s, i)
316
+ i = i + 1
317
+ }
318
+ result
319
+ }
320
+
321
+ // FreeLang 내장 함수 사용:
322
+ // - fetch(url, method, headers, body) -> str (비동기)
323
+ // - json_stringify(obj) -> str
324
+ // - json_parse(str) -> any
325
+ // - str(value) -> str
326
+ // - char_at(str, index) -> str
327
+ // - length(str) -> i32