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,161 @@
1
+ import { Lexer } from "./lexer";
2
+ import { Parser } from "./parser";
3
+ import { TypeChecker } from "./checker";
4
+ import { Compiler } from "./compiler";
5
+ import { VM } from "./vm";
6
+ import * as fs from "fs";
7
+
8
+ async function exec(source: string): Promise<{ output: string[]; error: string | null }> {
9
+ const { tokens, errors: lexErrors } = new Lexer(source).tokenize();
10
+ if (lexErrors.length > 0) {
11
+ return { output: [], error: `lex error: ${lexErrors[0].message}` };
12
+ }
13
+
14
+ const { program, errors: parseErrors } = new Parser(tokens).parse();
15
+ if (parseErrors.length > 0) {
16
+ return { output: [], error: `parse error: ${parseErrors[0].message}` };
17
+ }
18
+
19
+ const checkErrors = new TypeChecker().check(program);
20
+ if (checkErrors.length > 0) {
21
+ return { output: [], error: `type error: ${checkErrors[0].message}` };
22
+ }
23
+
24
+ const chunk = new Compiler().compile(program);
25
+ return await new VM().run(chunk);
26
+ }
27
+
28
+ describe("Database Operations", () => {
29
+ // Clean up test database files
30
+ afterEach(() => {
31
+ try {
32
+ if (fs.existsSync("./test_db.db")) {
33
+ fs.unlinkSync("./test_db.db");
34
+ }
35
+ } catch {
36
+ // ignore
37
+ }
38
+ });
39
+
40
+ it("sqlite_open: creates or opens database file", async () => {
41
+ const { output, error } = await exec(`
42
+ var db = sqlite_open("./test_db.db")
43
+ println("DB opened")
44
+ `);
45
+ expect(error).toBeNull();
46
+ expect(output).toContain("DB opened");
47
+ });
48
+
49
+ it("sqlite_execute: creates table and inserts data", async () => {
50
+ const { output, error } = await exec(`
51
+ var db = sqlite_open("./test_db.db")
52
+ var create_result = sqlite_execute(db, "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE)", [])
53
+ println("Table created")
54
+ var insert_result = sqlite_execute(db, "INSERT INTO users (name, email) VALUES (?, ?)", ["Alice", "alice@example.com"])
55
+ println("Record inserted")
56
+ `);
57
+ expect(error).toBeNull();
58
+ expect(output).toContain("Table created");
59
+ expect(output).toContain("Record inserted");
60
+ });
61
+
62
+ it("sqlite_query: retrieves data from table", async () => {
63
+ const { output, error } = await exec(`
64
+ var db = sqlite_open("./test_db.db")
65
+ sqlite_execute(db, "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT UNIQUE)", [])
66
+ sqlite_execute(db, "INSERT INTO users (name, email) VALUES (?, ?)", ["Alice", "alice@example.com"])
67
+ sqlite_execute(db, "INSERT INTO users (name, email) VALUES (?, ?)", ["Bob", "bob@example.com"])
68
+ var result = sqlite_query(db, "SELECT * FROM users", [])
69
+ println("Query complete")
70
+ `);
71
+ expect(error).toBeNull();
72
+ expect(output).toContain("Query complete");
73
+ });
74
+
75
+ it("sqlite_close: closes database", async () => {
76
+ const { output, error } = await exec(`
77
+ var db = sqlite_open("./test_db.db")
78
+ sqlite_close(db)
79
+ println("DB closed")
80
+ `);
81
+ expect(error).toBeNull();
82
+ expect(output).toContain("DB closed");
83
+ });
84
+
85
+ it("database handle error: invalid first argument", async () => {
86
+ const { output, error } = await exec(`
87
+ var result = sqlite_query("not a db", "SELECT 1", [])
88
+ println("Query attempted")
89
+ `);
90
+ // Should fail because first arg is not a database
91
+ expect(error || output.join(" ")).toBeTruthy();
92
+ });
93
+
94
+ it("sqlite_execute: returns ok result", async () => {
95
+ const { output, error } = await exec(`
96
+ var db = sqlite_open("./test_db.db")
97
+ sqlite_execute(db, "CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT NOT NULL)", [])
98
+ var result = sqlite_execute(db, "INSERT INTO items (name) VALUES (?)", ["Item1"])
99
+ println("Executed")
100
+ `);
101
+ expect(error).toBeNull();
102
+ expect(output).toContain("Executed");
103
+ });
104
+
105
+ it("sqlite_query: multiple rows", async () => {
106
+ const { output, error } = await exec(`
107
+ var db = sqlite_open("./test_db.db")
108
+ sqlite_execute(db, "CREATE TABLE IF NOT EXISTS people (id INTEGER PRIMARY KEY, name TEXT)", [])
109
+ sqlite_execute(db, "INSERT INTO people (name) VALUES (?)", ["Alice"])
110
+ sqlite_execute(db, "INSERT INTO people (name) VALUES (?)", ["Bob"])
111
+ sqlite_execute(db, "INSERT INTO people (name) VALUES (?)", ["Charlie"])
112
+ var rows = sqlite_query(db, "SELECT * FROM people", [])
113
+ println("All rows retrieved")
114
+ `);
115
+ expect(error).toBeNull();
116
+ expect(output).toContain("All rows retrieved");
117
+ });
118
+
119
+ it("sqlite_begin/commit: manual transaction", async () => {
120
+ const { output, error } = await exec(`
121
+ var db = sqlite_open("./test_db.db")
122
+ sqlite_execute(db, "CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY, balance INTEGER)", [])
123
+ sqlite_begin(db, "immediate")
124
+ sqlite_execute(db, "INSERT INTO accounts (balance) VALUES (?)", ["1000"])
125
+ sqlite_commit(db)
126
+ println("Transaction committed")
127
+ `);
128
+ expect(error).toBeNull();
129
+ expect(output).toContain("Transaction committed");
130
+ });
131
+
132
+ it("sqlite_begin/rollback: transaction rollback", async () => {
133
+ const { output, error } = await exec(`
134
+ var db = sqlite_open("./test_db.db")
135
+ sqlite_execute(db, "CREATE TABLE IF NOT EXISTS logs (id INTEGER PRIMARY KEY, message TEXT)", [])
136
+ sqlite_begin(db)
137
+ sqlite_execute(db, "INSERT INTO logs (message) VALUES (?)", ["Before rollback"])
138
+ sqlite_rollback(db)
139
+ var count = sqlite_query(db, "SELECT COUNT(*) as cnt FROM logs", [])
140
+ println("Rollback done")
141
+ `);
142
+ expect(error).toBeNull();
143
+ expect(output).toContain("Rollback done");
144
+ });
145
+
146
+ it("pg_connect: connection attempt (no server expected)", async () => {
147
+ const { output, error } = await exec(`
148
+ var result = pg_connect("localhost", "5432", "postgres", "password", "testdb")
149
+ println("pg_connect called")
150
+ `);
151
+ expect(output).toContain("pg_connect called");
152
+ });
153
+
154
+ it("mysql_connect: connection attempt (no server expected)", async () => {
155
+ const { output, error } = await exec(`
156
+ var result = mysql_connect("localhost", "3306", "root", "password", "testdb")
157
+ println("mysql_connect called")
158
+ `);
159
+ expect(output).toContain("mysql_connect called");
160
+ });
161
+ });
@@ -0,0 +1,242 @@
1
+ /**
2
+ * FreeLang v4 Database Runtime
3
+ * 100M Clone 데이터베이스 구축 및 테스트
4
+ */
5
+
6
+ import { Program, Stmt, Expr, Pattern } from './ast';
7
+ import { Lexer } from './lexer';
8
+ import { Parser } from './parser';
9
+
10
+ // ============================================================
11
+ // 데이터베이스 타입
12
+ // ============================================================
13
+
14
+ interface Record {
15
+ [key: string]: any;
16
+ }
17
+
18
+ interface Table {
19
+ schema: { [key: string]: string };
20
+ rows: Record[];
21
+ indices: Map<string, Map<any, number[]>>;
22
+ }
23
+
24
+ // ============================================================
25
+ // FreeLang v4 DB Runtime
26
+ // ============================================================
27
+
28
+ export class DBRuntime {
29
+ private tables: Map<string, Table> = new Map();
30
+ private variables: Map<string, any> = new Map();
31
+
32
+ // INSERT
33
+ insert(tableName: string, record: Record): boolean {
34
+ const table = this.tables.get(tableName);
35
+ if (!table) {
36
+ console.error(`Table "${tableName}" not found`);
37
+ return false;
38
+ }
39
+
40
+ // 스키마 검증
41
+ for (const [key, type] of Object.entries(table.schema)) {
42
+ if (!(key in record)) {
43
+ console.error(`Missing field "${key}" in record`);
44
+ return false;
45
+ }
46
+ }
47
+
48
+ table.rows.push(record);
49
+
50
+ // 인덱스 업데이트
51
+ for (const [field, index] of table.indices) {
52
+ const value = record[field];
53
+ if (!index.has(value)) {
54
+ index.set(value, []);
55
+ }
56
+ index.get(value)!.push(table.rows.length - 1);
57
+ }
58
+
59
+ return true;
60
+ }
61
+
62
+ // SELECT by ID
63
+ selectById(tableName: string, id: number): Record | null {
64
+ const table = this.tables.get(tableName);
65
+ if (!table) return null;
66
+
67
+ // 인덱스로 빠른 조회
68
+ const idIndex = table.indices.get('id');
69
+ if (idIndex && idIndex.has(id)) {
70
+ const indices = idIndex.get(id)!;
71
+ return table.rows[indices[0]] || null;
72
+ }
73
+
74
+ // 풀 스캔
75
+ for (const row of table.rows) {
76
+ if (row['id'] === id) return row;
77
+ }
78
+ return null;
79
+ }
80
+
81
+ // SELECT all
82
+ selectAll(tableName: string): Record[] {
83
+ const table = this.tables.get(tableName);
84
+ return table ? table.rows : [];
85
+ }
86
+
87
+ // CREATE TABLE
88
+ createTable(name: string, schema: { [key: string]: string }): void {
89
+ this.tables.set(name, {
90
+ schema,
91
+ rows: [],
92
+ indices: new Map([['id', new Map()]])
93
+ });
94
+ }
95
+
96
+ // STATS
97
+ getStats(tableName: string): { table: string; rows: number; memory_mb: number } {
98
+ const table = this.tables.get(tableName);
99
+ if (!table) return { table: tableName, rows: 0, memory_mb: 0 };
100
+
101
+ // 대략적인 메모리 계산 (JSON 직렬화)
102
+ const json = JSON.stringify(table.rows);
103
+ const memory_bytes = Buffer.byteLength(json, 'utf8');
104
+ const memory_mb = memory_bytes / (1024 * 1024);
105
+
106
+ return {
107
+ table: tableName,
108
+ rows: table.rows.length,
109
+ memory_mb: Math.round(memory_mb * 100) / 100
110
+ };
111
+ }
112
+
113
+ // BULK INSERT (고성능)
114
+ bulkInsert(tableName: string, records: Record[]): number {
115
+ const table = this.tables.get(tableName);
116
+ if (!table) return 0;
117
+
118
+ let count = 0;
119
+ for (const record of records) {
120
+ table.rows.push(record);
121
+
122
+ // 인덱스 업데이트
123
+ for (const [field, index] of table.indices) {
124
+ const value = record[field];
125
+ if (!index.has(value)) {
126
+ index.set(value, []);
127
+ }
128
+ index.get(value)!.push(table.rows.length - 1);
129
+ }
130
+ count++;
131
+ }
132
+ return count;
133
+ }
134
+ }
135
+
136
+ // ============================================================
137
+ // 메인: 100M Clone Database Test
138
+ // ============================================================
139
+
140
+ async function main() {
141
+ console.log('\n🚀 FreeLang v4 Database Runtime');
142
+ console.log('================================\n');
143
+
144
+ const db = new DBRuntime();
145
+
146
+ // 스키마 정의
147
+ db.createTable('clone_results', {
148
+ id: 'i32',
149
+ app: 'string',
150
+ clone_id: 'i32',
151
+ status: 'string',
152
+ test_time_ms: 'f64'
153
+ });
154
+
155
+ // Phase 1: 작은 규모 테스트
156
+ console.log('📊 Phase 1: Inserting 100K records...');
157
+ const start1 = Date.now();
158
+ for (let i = 0; i < 100000; i++) {
159
+ db.insert('clone_results', {
160
+ id: i,
161
+ app: ['proof_ai', 'cwm', 'freelang', 'kim_ai_os'][i % 4],
162
+ clone_id: i,
163
+ status: Math.random() > 0.01 ? 'success' : 'failed',
164
+ test_time_ms: Math.random() * 100
165
+ });
166
+ }
167
+ const time1 = Date.now() - start1;
168
+ let stats1 = db.getStats('clone_results');
169
+ console.log(`✅ 100K inserted in ${time1}ms`);
170
+ console.log(` Rows: ${stats1.rows}, Memory: ${stats1.memory_mb}MB\n`);
171
+
172
+ // Phase 2: 대규모 테스트 (100K → 1M)
173
+ console.log('📊 Phase 2: Scaling to 1M records...');
174
+ const start2 = Date.now();
175
+ for (let i = 100000; i < 1000000; i++) {
176
+ db.insert('clone_results', {
177
+ id: i,
178
+ app: ['proof_ai', 'cwm', 'freelang', 'kim_ai_os'][i % 4],
179
+ clone_id: i,
180
+ status: Math.random() > 0.01 ? 'success' : 'failed',
181
+ test_time_ms: Math.random() * 100
182
+ });
183
+ }
184
+ const time2 = Date.now() - start2;
185
+ stats1 = db.getStats('clone_results');
186
+ console.log(`✅ 900K inserted in ${time2}ms`);
187
+ console.log(` Total: ${stats1.rows} rows, Memory: ${stats1.memory_mb}MB\n`);
188
+
189
+ // Phase 3: 쿼리 성능 (SELECT)
190
+ console.log('📊 Phase 3: Query Performance...');
191
+ const queries = 10000;
192
+ const start3 = Date.now();
193
+ for (let i = 0; i < queries; i++) {
194
+ const randomId = Math.floor(Math.random() * 1000000);
195
+ db.selectById('clone_results', randomId);
196
+ }
197
+ const time3 = Date.now() - start3;
198
+ const qps = Math.round((queries / time3) * 1000);
199
+ console.log(`✅ ${queries} queries in ${time3}ms`);
200
+ console.log(` ${qps.toLocaleString()} queries/sec\n`);
201
+
202
+ // Phase 4: BULK INSERT 성능
203
+ console.log('📊 Phase 4: Bulk Insert (추가 100K)...');
204
+ const bulkRecords = [];
205
+ for (let i = 1000000; i < 1100000; i++) {
206
+ bulkRecords.push({
207
+ id: i,
208
+ app: ['proof_ai', 'cwm', 'freelang', 'kim_ai_os'][i % 4],
209
+ clone_id: i,
210
+ status: 'success',
211
+ test_time_ms: Math.random() * 100
212
+ });
213
+ }
214
+
215
+ const start4 = Date.now();
216
+ const inserted = db.bulkInsert('clone_results', bulkRecords);
217
+ const time4 = Date.now() - start4;
218
+ stats1 = db.getStats('clone_results');
219
+ console.log(`✅ ${inserted.toLocaleString()} records inserted in ${time4}ms`);
220
+ console.log(` Total: ${stats1.rows.toLocaleString()} rows, Memory: ${stats1.memory_mb}MB`);
221
+ console.log(` Rate: ${Math.round((inserted / time4) * 1000).toLocaleString()} inserts/sec\n`);
222
+
223
+ // 최종 리포트
224
+ console.log('═══════════════════════════════════════════════');
225
+ console.log('📊 FINAL REPORT');
226
+ console.log('═══════════════════════════════════════════════\n');
227
+
228
+ const finalStats = db.getStats('clone_results');
229
+ console.log(`Table: clone_results`);
230
+ console.log(`Total Records: ${finalStats.rows.toLocaleString()}`);
231
+ console.log(`Memory Used: ${finalStats.memory_mb}MB`);
232
+ console.log(`Avg Per Record: ${(finalStats.memory_mb * 1024 / finalStats.rows).toFixed(2)}KB\n`);
233
+
234
+ console.log(`Operations Summary:`);
235
+ console.log(` Phase 1 (100K): ${time1}ms`);
236
+ console.log(` Phase 2 (900K): ${time2}ms`);
237
+ console.log(` Phase 3 (Queries): ${time3}ms (${qps.toLocaleString()} qps)`);
238
+ console.log(` Phase 4 (Bulk): ${time4}ms (${Math.round((inserted / time4) * 1000).toLocaleString()} inserts/sec)`);
239
+ console.log('\n✅ FreeLang v4 Database Test Complete!');
240
+ }
241
+
242
+ main().catch(console.error);