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
package/src/main.ts ADDED
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env node
2
+ // FreeLang v4 — CLI Entry Point
3
+
4
+ import * as fs from "fs";
5
+ import { Lexer } from "./lexer";
6
+ import { Parser } from "./parser";
7
+ import { TypeChecker } from "./checker";
8
+ import { Compiler } from "./compiler";
9
+ import { VM } from "./vm";
10
+ import { IRGen } from "./ir-gen";
11
+ import { REPL } from "./repl";
12
+ import { SQLiteDB, MigrationManager } from "./db";
13
+
14
+ async function main(): Promise<void> {
15
+ const args = process.argv.slice(2);
16
+
17
+ // 버전 확인
18
+ if (args[0] === "--version" || args[0] === "-v") {
19
+ console.log("FreeLang 4.1.0");
20
+ process.exit(0);
21
+ }
22
+
23
+ // REPL 모드
24
+ if (args[0] === "--repl" || args[0] === "-i") {
25
+ const repl = new REPL();
26
+ await repl.start();
27
+ return;
28
+ }
29
+
30
+ // 마이그레이션 CLI
31
+ if (args[0] === "migrate") {
32
+ const cmd = args[1];
33
+ const dbPath = args[2] || "./app.db";
34
+ const migrationsDir = args[3] || "./migrations";
35
+
36
+ const db = new SQLiteDB(dbPath);
37
+ const manager = new MigrationManager(db, migrationsDir);
38
+
39
+ try {
40
+ if (cmd === "up") {
41
+ await db.init();
42
+ await manager.up();
43
+ await db.close();
44
+ } else if (cmd === "down") {
45
+ await db.init();
46
+ await manager.down();
47
+ await db.close();
48
+ } else if (cmd === "status") {
49
+ await db.init();
50
+ const rows = await manager.status();
51
+ if (rows.length === 0) {
52
+ console.log("적용된 마이그레이션이 없습니다.");
53
+ } else {
54
+ console.log("적용된 마이그레이션:");
55
+ for (const row of rows) {
56
+ console.log(` - ${row.name} (${row.applied_at})`);
57
+ }
58
+ }
59
+ await db.close();
60
+ } else {
61
+ console.error(`unknown migrate command: ${cmd}`);
62
+ console.log("Usage:");
63
+ console.log(" freelang migrate up [db_path] [migrations_dir]");
64
+ console.log(" freelang migrate down [db_path] [migrations_dir]");
65
+ console.log(" freelang migrate status [db_path] [migrations_dir]");
66
+ process.exit(1);
67
+ }
68
+ } catch (e: any) {
69
+ console.error(`migrate error: ${e.message}`);
70
+ process.exit(1);
71
+ }
72
+ return;
73
+ }
74
+
75
+ // 패키지 매니저 CLI
76
+ if (args[0] === "init") {
77
+ const { initProject } = await import("./pkg/init");
78
+ await initProject(args[1] || "my-app");
79
+ return;
80
+ }
81
+
82
+ if (args[0] === "install") {
83
+ const { installPackage } = await import("./pkg/install");
84
+ await installPackage(args[1], process.cwd());
85
+ return;
86
+ }
87
+
88
+ if (args[0] === "run") {
89
+ const { runScript } = await import("./pkg/run");
90
+ await runScript(args[1], process.cwd());
91
+ return;
92
+ }
93
+
94
+ if (args[0] === "list-packages") {
95
+ const { listPackages } = await import("./pkg/registry");
96
+ listPackages();
97
+ return;
98
+ }
99
+
100
+ if (args[0] === "search-packages") {
101
+ const { searchPackages } = await import("./pkg/registry");
102
+ searchPackages(args[1] || "");
103
+ return;
104
+ }
105
+
106
+ // 웹 REPL
107
+ if (args[0] === "--web-repl") {
108
+ const portIdx = args.indexOf("--port");
109
+ const port = portIdx >= 0 ? parseInt(args[portIdx + 1]) : 3000;
110
+ const { startWebRepl } = await import("./web-repl/server");
111
+ await startWebRepl(port);
112
+ return;
113
+ }
114
+
115
+ // 도움말
116
+ if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
117
+ console.log("🦁 FreeLang v4.3 — AI-First Programming Language");
118
+ console.log("");
119
+ console.log("Usage:");
120
+ console.log(" freelang <file.fl> [options] 파일 실행");
121
+ console.log(" freelang --repl 대화형 쉘 시작");
122
+ console.log(" freelang --web-repl [--port PORT] 웹 REPL 시작");
123
+ console.log("");
124
+ console.log("Project Management:");
125
+ console.log(" freelang init [name] 새 프로젝트 생성");
126
+ console.log(" freelang install <pkg> 패키지 설치");
127
+ console.log(" freelang run <script> freelang.toml 스크립트 실행");
128
+ console.log(" freelang list-packages 전체 패키지 목록");
129
+ console.log(" freelang search-packages <query> 패키지 검색");
130
+ console.log("");
131
+ console.log("Database:");
132
+ console.log(" freelang migrate <cmd> [args] 마이그레이션 관리");
133
+ console.log("");
134
+ console.log("Options:");
135
+ console.log(" --no-check 타입 체크 건너뛰기");
136
+ console.log(" --dump-bc 바이트코드 덤프");
137
+ console.log(" --dump-ir IR(중간 표현) 덤프");
138
+ console.log(" --use-ir IR 경로로 컴파일");
139
+ console.log(" --help, -h 도움말 표시");
140
+ console.log(" --version 버전 표시");
141
+ process.exit(0);
142
+ }
143
+
144
+ const file = args[0];
145
+ const noCheck = args.includes("--no-check");
146
+ const dumpBc = args.includes("--dump-bc");
147
+ const dumpIr = args.includes("--dump-ir");
148
+ const useIr = args.includes("--use-ir") || dumpIr;
149
+
150
+ // 파일 읽기
151
+ let source: string;
152
+ try {
153
+ source = fs.readFileSync(file, "utf-8");
154
+ } catch {
155
+ console.error(`error: cannot read file '${file}'`);
156
+ process.exit(1);
157
+ }
158
+
159
+ // 1. Lexer
160
+ const { tokens, errors: lexErrors } = new Lexer(source).tokenize();
161
+ if (lexErrors.length > 0) {
162
+ for (const e of lexErrors) {
163
+ console.error(`${file}:${e.line}: lex error: ${e.message}`);
164
+ }
165
+ process.exit(1);
166
+ }
167
+
168
+ // 2. Parser
169
+ const { program, errors: parseErrors } = new Parser(tokens).parse();
170
+ if (parseErrors.length > 0) {
171
+ for (const e of parseErrors) {
172
+ console.error(`${file}:${e.line}: parse error: ${e.message}`);
173
+ }
174
+ process.exit(1);
175
+ }
176
+
177
+ // 3. TypeChecker (optional)
178
+ if (!noCheck) {
179
+ const checkErrors = new TypeChecker().check(program);
180
+ if (checkErrors.length > 0) {
181
+ for (const e of checkErrors) {
182
+ console.error(`${file}:${e.line}: type error: ${e.message}`);
183
+ }
184
+ process.exit(1);
185
+ }
186
+ }
187
+
188
+ // 4. Compiler (IR 경로 vs 기존 경로)
189
+ let chunk;
190
+ if (useIr) {
191
+ const irProg = new IRGen().generate(program); // AST → IR
192
+ if (dumpIr) {
193
+ console.log(JSON.stringify(irProg, null, 2));
194
+ process.exit(0);
195
+ }
196
+ chunk = new Compiler().compileIR(irProg); // IR → Chunk
197
+ } else {
198
+ chunk = new Compiler().compile(program); // 기존 경로 유지
199
+ }
200
+
201
+ if (dumpBc) {
202
+ console.log(`--- bytecode (${chunk.code.length} bytes, ${chunk.functions.length} functions) ---`);
203
+ console.log(`constants: ${JSON.stringify(chunk.constants)}`);
204
+ for (const fn of chunk.functions) {
205
+ console.log(`fn ${fn.name}(arity=${fn.arity}) @ offset ${fn.offset}`);
206
+ }
207
+ process.exit(0);
208
+ }
209
+
210
+ // 5. VM 실행
211
+ const { output, error } = await new VM().run(chunk);
212
+
213
+ for (const line of output) {
214
+ console.log(line);
215
+ }
216
+
217
+ if (error) {
218
+ console.error(error);
219
+ process.exit(1);
220
+ }
221
+ }
222
+
223
+ main().catch(console.error);
package/src/models.fl ADDED
@@ -0,0 +1,162 @@
1
+ // FreeLang v4.2 — gogs-cli API 응답 모델
2
+ // Gogs API에서 반환하는 데이터 구조
3
+
4
+ // ==================== Repo Model ====================
5
+
6
+ struct Repo {
7
+ id: i32
8
+ owner: Owner
9
+ name: str
10
+ full_name: str
11
+ description: str
12
+ private: bool
13
+ fork: bool
14
+ html_url: str
15
+ ssh_url: str
16
+ clone_url: str
17
+ default_branch: str
18
+ created_at: str
19
+ updated_at: str
20
+ }
21
+
22
+ struct Owner {
23
+ id: i32
24
+ login: str
25
+ avatar_url: str
26
+ }
27
+
28
+ struct CreateRepoRequest {
29
+ name: str
30
+ description: str
31
+ private: bool
32
+ }
33
+
34
+ // ==================== User Model ====================
35
+
36
+ struct User {
37
+ id: i32
38
+ login: str
39
+ full_name: str
40
+ email: str
41
+ is_admin: bool
42
+ avatar_url: str
43
+ created_at: str
44
+ updated_at: str
45
+ }
46
+
47
+ struct CreateUserRequest {
48
+ username: str
49
+ email: str
50
+ password: str
51
+ send_notify: bool
52
+ is_admin: bool
53
+ }
54
+
55
+ // ==================== Organization Model ====================
56
+
57
+ struct Organization {
58
+ id: i32
59
+ username: str
60
+ full_name: str
61
+ email: str
62
+ website: str
63
+ location: str
64
+ bio: str
65
+ avatar_url: str
66
+ created_at: str
67
+ updated_at: str
68
+ }
69
+
70
+ struct CreateOrgRequest {
71
+ username: str
72
+ full_name: str
73
+ email: str
74
+ website: str
75
+ location: str
76
+ bio: str
77
+ }
78
+
79
+ // ==================== Team Model ====================
80
+
81
+ struct Team {
82
+ id: i32
83
+ name: str
84
+ description: str
85
+ permission: str
86
+ }
87
+
88
+ struct CreateTeamRequest {
89
+ name: str
90
+ description: str
91
+ permission: str
92
+ }
93
+
94
+ // ==================== Issue Model ====================
95
+
96
+ struct Issue {
97
+ id: i32
98
+ number: i32
99
+ title: str
100
+ description: str
101
+ state: str // "open", "closed"
102
+ user: User
103
+ created_at: str
104
+ updated_at: str
105
+ }
106
+
107
+ struct CreateIssueRequest {
108
+ title: str
109
+ body: str
110
+ }
111
+
112
+ // ==================== Webhook Model ====================
113
+
114
+ struct Webhook {
115
+ id: i32
116
+ url: str
117
+ content_type: str
118
+ events: [str]
119
+ active: bool
120
+ created_at: str
121
+ updated_at: str
122
+ }
123
+
124
+ struct CreateWebhookRequest {
125
+ url: str
126
+ content_type: str
127
+ events: [str]
128
+ active: bool
129
+ }
130
+
131
+ // ==================== Deploy Key Model ====================
132
+
133
+ struct DeployKey {
134
+ id: i32
135
+ key_id: i32
136
+ title: str
137
+ key: str
138
+ url: str
139
+ read_only: bool
140
+ created_at: str
141
+ }
142
+
143
+ struct CreateDeployKeyRequest {
144
+ title: str
145
+ key: str
146
+ read_only: bool
147
+ }
148
+
149
+ // ==================== Analysis Model ====================
150
+
151
+ struct RepositoryStats {
152
+ total: i32
153
+ public: i32
154
+ private: i32
155
+ recently_updated_7days: i32
156
+ by_updated: [Repo]
157
+ }
158
+
159
+ struct AnalysisResult {
160
+ timestamp: str
161
+ repository_stats: RepositoryStats
162
+ }
@@ -0,0 +1,145 @@
1
+ // FreeLang v4 Module System Tests
2
+ // 기본 import/export 파싱 및 검증 테스트
3
+
4
+ import { Lexer } from "./lexer";
5
+ import { Parser } from "./parser";
6
+ import { TypeChecker } from "./checker";
7
+ import { Program, Stmt, ImportDecl, ExportDecl } from "./ast";
8
+
9
+ describe("Module System", () => {
10
+ // 헬퍼: 코드를 AST로 파싱
11
+ function parseCode(code: string): Program {
12
+ const lexer = new Lexer(code);
13
+ const { tokens, errors: lexErrors } = lexer.tokenize();
14
+ if (lexErrors.length > 0) {
15
+ throw new Error(`Lex errors: ${lexErrors.map(e => e.message).join(", ")}`);
16
+ }
17
+
18
+ const parser = new Parser(tokens);
19
+ const { program, errors: parseErrors } = parser.parse();
20
+ if (parseErrors.length > 0) {
21
+ throw new Error(`Parse errors: ${parseErrors.map(e => e.message).join(", ")}`);
22
+ }
23
+
24
+ return program;
25
+ }
26
+
27
+ // Test 1: 기본 import 파싱
28
+ it("should parse basic import statement", () => {
29
+ const code = `import { add } from "./math";`;
30
+ const program = parseCode(code);
31
+
32
+ expect(program.stmts.length).toBe(1);
33
+ const stmt = program.stmts[0] as ImportDecl;
34
+ expect(stmt.kind).toBe("import_decl");
35
+ expect(stmt.source).toBe("./math");
36
+ expect(stmt.items.length).toBe(1);
37
+ expect(stmt.items[0].name).toBe("add");
38
+ expect(stmt.items[0].alias).toBeUndefined();
39
+ });
40
+
41
+ // Test 2: 다중 항목 import
42
+ it("should parse multiple import items", () => {
43
+ const code = `import { add, subtract, multiply } from "./math";`;
44
+ const program = parseCode(code);
45
+
46
+ const stmt = program.stmts[0] as ImportDecl;
47
+ expect(stmt.items.length).toBe(3);
48
+ expect(stmt.items[0].name).toBe("add");
49
+ expect(stmt.items[1].name).toBe("subtract");
50
+ expect(stmt.items[2].name).toBe("multiply");
51
+ });
52
+
53
+ // Test 3: Import alias
54
+ it("should parse import with alias", () => {
55
+ const code = `import { add as sum } from "./math";`;
56
+ const program = parseCode(code);
57
+
58
+ const stmt = program.stmts[0] as ImportDecl;
59
+ expect(stmt.items[0].name).toBe("add");
60
+ expect(stmt.items[0].alias).toBe("sum");
61
+ });
62
+
63
+ // Test 4: Default import
64
+ it("should parse default import", () => {
65
+ const code = `import math from "./math";`;
66
+ const program = parseCode(code);
67
+
68
+ const stmt = program.stmts[0] as ImportDecl;
69
+ expect(stmt.default).toBe(true);
70
+ expect(stmt.items[0].name).toBe("math");
71
+ });
72
+
73
+ // Test 5: Export with function
74
+ it("should parse export function", () => {
75
+ const code = `export fn add(a: i32, b: i32) -> i32 { a + b }`;
76
+ const program = parseCode(code);
77
+
78
+ const stmt = program.stmts[0] as ExportDecl;
79
+ expect(stmt.kind).toBe("export_decl");
80
+ expect(typeof stmt.target).not.toBe("string");
81
+ });
82
+
83
+ // Test 6: Export with struct
84
+ it("should parse export struct", () => {
85
+ const code = `export struct Point { x: i32, y: i32 }`;
86
+ const program = parseCode(code);
87
+
88
+ const stmt = program.stmts[0] as ExportDecl;
89
+ expect(stmt.kind).toBe("export_decl");
90
+ });
91
+
92
+ // Test 7: Export list
93
+ it("should parse export list", () => {
94
+ const code = `export { add, multiply, PI };`;
95
+ const program = parseCode(code);
96
+
97
+ const stmt = program.stmts[0] as ExportDecl;
98
+ expect(typeof stmt.target).toBe("object");
99
+ const names = stmt.target as string[];
100
+ expect(names.length).toBe(3);
101
+ expect(names[0]).toBe("add");
102
+ expect(names[1]).toBe("multiply");
103
+ expect(names[2]).toBe("PI");
104
+ });
105
+
106
+ // Test 8: Type checking with imports
107
+ it("should check imported names in scope", () => {
108
+ const code = `
109
+ import { add } from "./math";
110
+ var result: i32 = add(2, 3);
111
+ `;
112
+ const program = parseCode(code);
113
+ const checker = new TypeChecker();
114
+ const errors = checker.check(program);
115
+
116
+ // import 문이 성공적으로 처리되어야 함
117
+ expect(errors.length).toBeLessThan(3); // 약간의 에러는 있을 수 있음 (모듈 미로드)
118
+ });
119
+
120
+ // Test 9: Multiple imports
121
+ it("should parse multiple import statements", () => {
122
+ const code = `
123
+ import { add } from "./math";
124
+ import { map, filter } from "./array";
125
+ fn main() -> void { }
126
+ `;
127
+ const program = parseCode(code);
128
+
129
+ expect(program.stmts[0].kind).toBe("import_decl");
130
+ expect(program.stmts[1].kind).toBe("import_decl");
131
+ expect(program.stmts[2].kind).toBe("fn_decl");
132
+ });
133
+
134
+ // Test 10: Import and Export together
135
+ it("should parse import and export together", () => {
136
+ const code = `
137
+ import { double } from "./utils";
138
+ export fn quad(x: i32) -> i32 { double(double(x)) }
139
+ `;
140
+ const program = parseCode(code);
141
+
142
+ expect(program.stmts[0].kind).toBe("import_decl");
143
+ expect(program.stmts[1].kind).toBe("export_decl");
144
+ });
145
+ });