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,542 @@
1
+ // FreeLang v4 — Parser 테스트
2
+
3
+ import { Lexer } from "./lexer";
4
+ import { Parser } from "./parser";
5
+ import { Stmt, Expr } from "./ast";
6
+
7
+ function parse(source: string): { stmts: Stmt[]; errors: string[] } {
8
+ const { tokens, errors: lexErrors } = new Lexer(source).tokenize();
9
+ if (lexErrors.length > 0) throw new Error(`Lex error: ${lexErrors[0].message}`);
10
+ const { program, errors } = new Parser(tokens).parse();
11
+ return { stmts: program.stmts, errors: errors.map((e) => e.message) };
12
+ }
13
+
14
+ function parseOk(source: string): Stmt[] {
15
+ const { stmts, errors } = parse(source);
16
+ if (errors.length > 0) throw new Error(`Parse errors: ${errors.join(", ")}`);
17
+ return stmts;
18
+ }
19
+
20
+ function parseExpr(source: string): Expr {
21
+ const stmts = parseOk(source);
22
+ if (stmts.length !== 1 || stmts[0].kind !== "expr_stmt") {
23
+ throw new Error("expected single expr_stmt");
24
+ }
25
+ return (stmts[0] as any).expr;
26
+ }
27
+
28
+ let passed = 0;
29
+ let failed = 0;
30
+
31
+ function assert(cond: boolean, msg: string) {
32
+ if (cond) {
33
+ passed++;
34
+ } else {
35
+ failed++;
36
+ console.error(` ❌ FAIL: ${msg}`);
37
+ }
38
+ }
39
+
40
+ // ============================================================
41
+ // 1. 변수 선언 (var/let/const)
42
+ // ============================================================
43
+
44
+ console.log("=== 변수 선언 ===");
45
+
46
+ {
47
+ const [s] = parseOk("var x: i32 = 42");
48
+ assert(s.kind === "var_decl", "var_decl kind");
49
+ assert((s as any).name === "x", "name = x");
50
+ assert((s as any).mutable === true, "var is mutable");
51
+ assert((s as any).type?.kind === "i32", "type = i32");
52
+ assert((s as any).init.kind === "int_lit", "init = int_lit");
53
+ console.log(" ✅ var x: i32 = 42");
54
+ }
55
+
56
+ {
57
+ const [s] = parseOk('let name = "hello"');
58
+ assert(s.kind === "var_decl", "let → var_decl");
59
+ assert((s as any).mutable === false, "let is immutable");
60
+ assert((s as any).type === null, "type inferred");
61
+ console.log(" ✅ let name = \"hello\"");
62
+ }
63
+
64
+ {
65
+ const [s] = parseOk("const PI: f64 = 3.14");
66
+ assert(s.kind === "var_decl", "const → var_decl");
67
+ assert((s as any).mutable === false, "const is immutable");
68
+ assert((s as any).type?.kind === "f64", "type = f64");
69
+ console.log(" ✅ const PI: f64 = 3.14");
70
+ }
71
+
72
+ // ============================================================
73
+ // 2. 함수 선언
74
+ // ============================================================
75
+
76
+ console.log("=== 함수 선언 ===");
77
+
78
+ {
79
+ const [s] = parseOk("fn add(a: i32, b: i32): i32 { return a + b }");
80
+ assert(s.kind === "fn_decl", "fn_decl kind");
81
+ const f = s as any;
82
+ assert(f.name === "add", "name = add");
83
+ assert(f.params.length === 2, "2 params");
84
+ assert(f.params[0].name === "a", "param a");
85
+ assert(f.params[0].type.kind === "i32", "param a: i32");
86
+ assert(f.returnType.kind === "i32", "return i32");
87
+ assert(f.body.length === 1, "1 stmt in body");
88
+ assert(f.body[0].kind === "return_stmt", "return stmt");
89
+ console.log(" ✅ fn add(a: i32, b: i32): i32");
90
+ }
91
+
92
+ {
93
+ const [s] = parseOk("fn noop(): void { }");
94
+ const f = s as any;
95
+ assert(f.name === "noop", "name = noop");
96
+ assert(f.params.length === 0, "0 params");
97
+ assert(f.returnType.kind === "void", "return void");
98
+ console.log(" ✅ fn noop(): void");
99
+ }
100
+
101
+ // ============================================================
102
+ // 3. 식 — 리터럴
103
+ // ============================================================
104
+
105
+ console.log("=== 리터럴 ===");
106
+
107
+ {
108
+ const e = parseExpr("42");
109
+ assert(e.kind === "int_lit" && (e as any).value === 42, "42");
110
+ console.log(" ✅ 42");
111
+ }
112
+
113
+ {
114
+ const e = parseExpr("3.14");
115
+ assert(e.kind === "float_lit" && (e as any).value === 3.14, "3.14");
116
+ console.log(" ✅ 3.14");
117
+ }
118
+
119
+ {
120
+ const e = parseExpr('"hello"');
121
+ assert(e.kind === "string_lit" && (e as any).value === "hello", '"hello"');
122
+ console.log(' ✅ "hello"');
123
+ }
124
+
125
+ {
126
+ const e = parseExpr("true");
127
+ assert(e.kind === "bool_lit" && (e as any).value === true, "true");
128
+ console.log(" ✅ true");
129
+ }
130
+
131
+ {
132
+ const e = parseExpr("false");
133
+ assert(e.kind === "bool_lit" && (e as any).value === false, "false");
134
+ console.log(" ✅ false");
135
+ }
136
+
137
+ // ============================================================
138
+ // 4. 식 — 이항 연산 + 우선순위
139
+ // ============================================================
140
+
141
+ console.log("=== 이항 연산 ===");
142
+
143
+ {
144
+ // 1 + 2 * 3 → +(1, *(2, 3))
145
+ const e = parseExpr("1 + 2 * 3") as any;
146
+ assert(e.kind === "binary" && e.op === "+", "top = +");
147
+ assert(e.left.kind === "int_lit" && e.left.value === 1, "left = 1");
148
+ assert(e.right.kind === "binary" && e.right.op === "*", "right = *");
149
+ assert(e.right.left.value === 2, "2 * 3 left");
150
+ assert(e.right.right.value === 3, "2 * 3 right");
151
+ console.log(" ✅ 1 + 2 * 3 → +(1, *(2, 3))");
152
+ }
153
+
154
+ {
155
+ // a && b || c → ||(&&(a, b), c)
156
+ const e = parseExpr("a && b || c") as any;
157
+ assert(e.kind === "binary" && e.op === "||", "top = ||");
158
+ assert(e.left.op === "&&", "left = &&");
159
+ console.log(" ✅ a && b || c → ||(&&(a, b), c)");
160
+ }
161
+
162
+ {
163
+ // x == 1 && y != 2
164
+ const e = parseExpr("x == 1 && y != 2") as any;
165
+ assert(e.op === "&&", "top = &&");
166
+ assert(e.left.op === "==", "left = ==");
167
+ assert(e.right.op === "!=", "right = !=");
168
+ console.log(" ✅ x == 1 && y != 2");
169
+ }
170
+
171
+ // ============================================================
172
+ // 5. 식 — 단항 연산
173
+ // ============================================================
174
+
175
+ console.log("=== 단항 연산 ===");
176
+
177
+ {
178
+ const e = parseExpr("-42") as any;
179
+ assert(e.kind === "unary" && e.op === "-", "unary -");
180
+ assert(e.operand.value === 42, "operand 42");
181
+ console.log(" ✅ -42");
182
+ }
183
+
184
+ {
185
+ const e = parseExpr("!flag") as any;
186
+ assert(e.kind === "unary" && e.op === "!", "unary !");
187
+ assert(e.operand.name === "flag", "operand flag");
188
+ console.log(" ✅ !flag");
189
+ }
190
+
191
+ // ============================================================
192
+ // 6. 식 — 함수 호출
193
+ // ============================================================
194
+
195
+ console.log("=== 함수 호출 ===");
196
+
197
+ {
198
+ const e = parseExpr("add(1, 2)") as any;
199
+ assert(e.kind === "call", "call");
200
+ assert(e.callee.name === "add", "callee = add");
201
+ assert(e.args.length === 2, "2 args");
202
+ console.log(" ✅ add(1, 2)");
203
+ }
204
+
205
+ {
206
+ const e = parseExpr("println()") as any;
207
+ assert(e.kind === "call" && e.args.length === 0, "0 args");
208
+ console.log(" ✅ println()");
209
+ }
210
+
211
+ // 체이닝: foo.bar(1)
212
+ {
213
+ const e = parseExpr("foo.bar(1)") as any;
214
+ assert(e.kind === "call", "call");
215
+ assert(e.callee.kind === "field_access", "callee = field_access");
216
+ assert(e.callee.field === "bar", "field = bar");
217
+ console.log(" ✅ foo.bar(1)");
218
+ }
219
+
220
+ // ============================================================
221
+ // 7. 식 — 인덱스, 필드 접근
222
+ // ============================================================
223
+
224
+ console.log("=== 인덱스 & 필드 접근 ===");
225
+
226
+ {
227
+ const e = parseExpr("arr[0]") as any;
228
+ assert(e.kind === "index", "index");
229
+ assert(e.object.name === "arr", "object = arr");
230
+ assert(e.index.value === 0, "index = 0");
231
+ console.log(" ✅ arr[0]");
232
+ }
233
+
234
+ {
235
+ const e = parseExpr("point.x") as any;
236
+ assert(e.kind === "field_access", "field_access");
237
+ assert(e.field === "x", "field = x");
238
+ console.log(" ✅ point.x");
239
+ }
240
+
241
+ // ============================================================
242
+ // 8. 식 — try 연산자 (?)
243
+ // ============================================================
244
+
245
+ console.log("=== try 연산자 ===");
246
+
247
+ {
248
+ const e = parseExpr("getValue()") as any;
249
+ assert(e.kind === "call", "call");
250
+ console.log(" ✅ getValue()");
251
+ }
252
+
253
+ // ch.recv()? 형태 테스트 — 함수 내 return 문으로 테스트
254
+ {
255
+ const stmts = parseOk("fn f(): Result<i32, string> { return ch.recv()? }");
256
+ const ret = (stmts[0] as any).body[0];
257
+ assert(ret.kind === "return_stmt", "return_stmt");
258
+ assert(ret.value.kind === "try", "try op");
259
+ assert(ret.value.operand.kind === "call", "call inside try");
260
+ console.log(" ✅ ch.recv()?");
261
+ }
262
+
263
+ // ============================================================
264
+ // 9. 식 — 배열/구조체 리터럴
265
+ // ============================================================
266
+
267
+ console.log("=== 배열 & 구조체 리터럴 ===");
268
+
269
+ {
270
+ const e = parseExpr("[1, 2, 3]") as any;
271
+ assert(e.kind === "array_lit", "array_lit");
272
+ assert(e.elements.length === 3, "3 elements");
273
+ console.log(" ✅ [1, 2, 3]");
274
+ }
275
+
276
+ {
277
+ const stmts = parseOk('var p = { x: 1, y: 2 }');
278
+ const init = (stmts[0] as any).init;
279
+ assert(init.kind === "struct_lit", "struct_lit");
280
+ assert(init.fields.length === 2, "2 fields");
281
+ assert(init.fields[0].name === "x", "field x");
282
+ assert(init.fields[1].name === "y", "field y");
283
+ console.log(" ✅ { x: 1, y: 2 }");
284
+ }
285
+
286
+ // ============================================================
287
+ // 10. if 문
288
+ // ============================================================
289
+
290
+ console.log("=== if 문 ===");
291
+
292
+ {
293
+ const [s] = parseOk('if x > 0 { println("pos") }');
294
+ assert(s.kind === "if_stmt", "if_stmt");
295
+ const i = s as any;
296
+ assert(i.condition.op === ">", "condition >");
297
+ assert(i.then.length === 1, "then 1 stmt");
298
+ assert(i.else_ === null, "no else");
299
+ console.log(" ✅ if x > 0 { ... }");
300
+ }
301
+
302
+ {
303
+ const [s] = parseOk('if x > 0 { println("pos") } else { println("neg") }');
304
+ const i = s as any;
305
+ assert(i.else_ !== null, "has else");
306
+ assert(i.else_.length === 1, "else 1 stmt");
307
+ console.log(" ✅ if ... else ...");
308
+ }
309
+
310
+ // else if 체인
311
+ {
312
+ const [s] = parseOk('if x > 0 { println("pos") } else if x == 0 { println("zero") } else { println("neg") }');
313
+ const i = s as any;
314
+ assert(i.else_.length === 1, "else branch = 1 if_stmt");
315
+ assert(i.else_[0].kind === "if_stmt", "else if chain");
316
+ console.log(" ✅ if ... else if ... else ...");
317
+ }
318
+
319
+ // ============================================================
320
+ // 11. for 문
321
+ // ============================================================
322
+
323
+ console.log("=== for 문 ===");
324
+
325
+ {
326
+ const [s] = parseOk("for item in items { println(item) }");
327
+ assert(s.kind === "for_stmt", "for_stmt");
328
+ const f = s as any;
329
+ assert(f.variable === "item", "variable = item");
330
+ assert(f.iterable.name === "items", "iterable = items");
331
+ assert(f.body.length === 1, "1 stmt in body");
332
+ console.log(" ✅ for item in items { ... }");
333
+ }
334
+
335
+ // range 패턴
336
+ {
337
+ const [s] = parseOk("for i in range(0, 10) { println(i) }");
338
+ const f = s as any;
339
+ assert(f.iterable.kind === "call", "iterable = call");
340
+ assert(f.iterable.callee.name === "range", "callee = range");
341
+ console.log(" ✅ for i in range(0, 10) { ... }");
342
+ }
343
+
344
+ // ============================================================
345
+ // 12. match 문
346
+ // ============================================================
347
+
348
+ console.log("=== match 문 ===");
349
+
350
+ {
351
+ const [s] = parseOk(`match x {
352
+ 0 => println("zero")
353
+ 1 => println("one")
354
+ _ => println("other")
355
+ }`);
356
+ assert(s.kind === "match_stmt", "match_stmt");
357
+ const m = s as any;
358
+ assert(m.arms.length === 3, "3 arms");
359
+ assert(m.arms[0].pattern.kind === "literal", "arm 0 literal");
360
+ assert(m.arms[2].pattern.kind === "wildcard", "arm 2 wildcard");
361
+ console.log(" ✅ match x { 0 => ..., 1 => ..., _ => ... }");
362
+ }
363
+
364
+ {
365
+ const [s] = parseOk(`match result {
366
+ Ok(v) => v
367
+ Err(e) => 0
368
+ }`);
369
+ const m = s as any;
370
+ assert(m.arms[0].pattern.kind === "ok", "Ok pattern");
371
+ assert(m.arms[0].pattern.inner.kind === "ident", "Ok inner = ident");
372
+ assert(m.arms[1].pattern.kind === "err", "Err pattern");
373
+ console.log(" ✅ match result { Ok(v) => ..., Err(e) => ... }");
374
+ }
375
+
376
+ {
377
+ const [s] = parseOk(`match opt {
378
+ Some(v) => v
379
+ None => 0
380
+ }`);
381
+ const m = s as any;
382
+ assert(m.arms[0].pattern.kind === "some", "Some pattern");
383
+ assert(m.arms[1].pattern.kind === "none", "None pattern");
384
+ console.log(" ✅ match opt { Some(v) => ..., None => ... }");
385
+ }
386
+
387
+ // ============================================================
388
+ // 13. spawn 문
389
+ // ============================================================
390
+
391
+ console.log("=== spawn 문 ===");
392
+
393
+ {
394
+ const [s] = parseOk('spawn { println("actor") }');
395
+ assert(s.kind === "spawn_stmt", "spawn_stmt");
396
+ assert((s as any).body.length === 1, "1 stmt");
397
+ console.log(" ✅ spawn { ... }");
398
+ }
399
+
400
+ // ============================================================
401
+ // 14. return 문
402
+ // ============================================================
403
+
404
+ console.log("=== return 문 ===");
405
+
406
+ {
407
+ const stmts = parseOk("fn f(): i32 { return 42 }");
408
+ const body = (stmts[0] as any).body;
409
+ assert(body[0].kind === "return_stmt", "return_stmt");
410
+ assert(body[0].value.value === 42, "return 42");
411
+ console.log(" ✅ return 42");
412
+ }
413
+
414
+ {
415
+ const stmts = parseOk("fn f(): void { return }");
416
+ const body = (stmts[0] as any).body;
417
+ assert(body[0].kind === "return_stmt", "return_stmt");
418
+ assert(body[0].value === null, "return void");
419
+ console.log(" ✅ return (void)");
420
+ }
421
+
422
+ // ============================================================
423
+ // 15. 할당
424
+ // ============================================================
425
+
426
+ console.log("=== 할당 ===");
427
+
428
+ {
429
+ const [s] = parseOk("x = 42");
430
+ assert(s.kind === "expr_stmt", "expr_stmt");
431
+ const e = (s as any).expr;
432
+ assert(e.kind === "assign", "assign");
433
+ assert(e.target.name === "x", "target = x");
434
+ assert(e.value.value === 42, "value = 42");
435
+ console.log(" ✅ x = 42");
436
+ }
437
+
438
+ {
439
+ const [s] = parseOk("arr[0] = 10");
440
+ const e = (s as any).expr;
441
+ assert(e.kind === "assign", "assign");
442
+ assert(e.target.kind === "index", "target = index");
443
+ console.log(" ✅ arr[0] = 10");
444
+ }
445
+
446
+ // ============================================================
447
+ // 16. 타입 파싱
448
+ // ============================================================
449
+
450
+ console.log("=== 타입 파싱 ===");
451
+
452
+ {
453
+ const [s] = parseOk("var x: [i32] = [1, 2, 3]");
454
+ assert((s as any).type.kind === "array", "array type");
455
+ assert((s as any).type.element.kind === "i32", "element = i32");
456
+ console.log(" ✅ [i32]");
457
+ }
458
+
459
+ {
460
+ const [s] = parseOk("var ch: channel<i32> = channel(0)");
461
+ assert((s as any).type.kind === "channel", "channel type");
462
+ console.log(" ✅ channel<i32>");
463
+ }
464
+
465
+ {
466
+ const [s] = parseOk("var opt: Option<string> = None");
467
+ assert((s as any).type.kind === "option", "option type");
468
+ console.log(" ✅ Option<string>");
469
+ }
470
+
471
+ {
472
+ const [s] = parseOk("var res: Result<i32, string> = Ok(42)");
473
+ assert((s as any).type.kind === "result", "result type");
474
+ assert((s as any).type.ok.kind === "i32", "ok = i32");
475
+ assert((s as any).type.err.kind === "string", "err = string");
476
+ console.log(" ✅ Result<i32, string>");
477
+ }
478
+
479
+ // ============================================================
480
+ // 17. 통합 테스트 — SPEC_05 Q10 테스트 프로그램
481
+ // ============================================================
482
+
483
+ console.log("=== 통합 테스트 ===");
484
+
485
+ // 테스트 1: var + 함수 호출
486
+ {
487
+ const stmts = parseOk(`var result = add(1, 2 * 3)
488
+ println(result)`);
489
+ assert(stmts.length === 2, "2 stmts");
490
+ assert(stmts[0].kind === "var_decl", "var_decl");
491
+ assert(stmts[1].kind === "expr_stmt", "expr_stmt");
492
+ console.log(" ✅ 통합 1: var + call");
493
+ }
494
+
495
+ // 테스트 2: match + 필드 접근
496
+ {
497
+ const stmts = parseOk(`match ch.recv() {
498
+ Ok(v) => v + 1,
499
+ Err(e) => 0,
500
+ }`);
501
+ assert(stmts[0].kind === "match_stmt", "match_stmt");
502
+ const m = stmts[0] as any;
503
+ assert(m.subject.kind === "call", "subject = call");
504
+ assert(m.arms.length === 2, "2 arms");
505
+ console.log(" ✅ 통합 2: match ch.recv()");
506
+ }
507
+
508
+ // 테스트 3: 중첩 함수
509
+ {
510
+ const stmts = parseOk(`fn factorial(n: i32): i32 {
511
+ if n <= 1 {
512
+ return 1
513
+ }
514
+ return n * factorial(n + -1)
515
+ }`);
516
+ assert(stmts[0].kind === "fn_decl", "fn_decl");
517
+ const f = stmts[0] as any;
518
+ assert(f.name === "factorial", "name = factorial");
519
+ assert(f.body.length === 2, "2 stmts in body");
520
+ console.log(" ✅ 통합 3: factorial");
521
+ }
522
+
523
+ // 테스트 4: for + match
524
+ {
525
+ const stmts = parseOk(`for item in items {
526
+ match item {
527
+ 0 => println("zero"),
528
+ _ => println("other"),
529
+ }
530
+ }`);
531
+ assert(stmts[0].kind === "for_stmt", "for_stmt");
532
+ const forBody = (stmts[0] as any).body;
533
+ assert(forBody[0].kind === "match_stmt", "nested match");
534
+ console.log(" ✅ 통합 4: for + match");
535
+ }
536
+
537
+ // ============================================================
538
+ // 결과
539
+ // ============================================================
540
+
541
+ console.log(`\n=== 결과: ${passed} passed, ${failed} failed ===`);
542
+ if (failed > 0) process.exit(1);