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,189 @@
1
+ // FreeLang v4 — TypeChecker 테스트 - Jest Format
2
+
3
+ import { Lexer } from "./lexer";
4
+ import { Parser } from "./parser";
5
+ import { TypeChecker, CheckError } from "./checker";
6
+
7
+ function check(source: string): CheckError[] {
8
+ const { tokens, errors: lexErrors } = new Lexer(source).tokenize();
9
+ if (lexErrors.length > 0) throw new Error(`Lex: ${lexErrors[0].message}`);
10
+ const { program, errors: parseErrors } = new Parser(tokens).parse();
11
+ if (parseErrors.length > 0) throw new Error(`Parse: ${parseErrors[0].message}`);
12
+ return new TypeChecker().check(program);
13
+ }
14
+
15
+ // ============================================================
16
+ // Jest Tests
17
+ // ============================================================
18
+
19
+ describe("TypeChecker Tests", () => {
20
+ describe("타입 추론", () => {
21
+ it("var x = 42 (i32 추론)", () => {
22
+ const errors = check("var x = 42");
23
+ expect(errors.length).toBe(0);
24
+ });
25
+
26
+ it("var x = 3.14 (f64 추론)", () => {
27
+ const errors = check("var x = 3.14");
28
+ expect(errors.length).toBe(0);
29
+ });
30
+
31
+ it('var x = "hello" (string 추론)', () => {
32
+ const errors = check('var x = "hello"');
33
+ expect(errors.length).toBe(0);
34
+ });
35
+
36
+ it("var x = true (bool 추론)", () => {
37
+ const errors = check("var x = true");
38
+ expect(errors.length).toBe(0);
39
+ });
40
+
41
+ it("var x: i32 = 42", () => {
42
+ const errors = check("var x: i32 = 42");
43
+ expect(errors.length).toBe(0);
44
+ });
45
+
46
+ it("var x: f64 = 3.14", () => {
47
+ const errors = check("var x: f64 = 3.14");
48
+ expect(errors.length).toBe(0);
49
+ });
50
+ });
51
+
52
+ describe("타입 불일치", () => {
53
+ it("i32 = string 불일치", () => {
54
+ const errors = check('var x: i32 = "hello"');
55
+ expect(errors.length).toBeGreaterThan(0);
56
+ expect(errors[0].message).toContain("type mismatch");
57
+ });
58
+
59
+ it("bool = i32 불일치", () => {
60
+ const errors = check("var x: bool = 42");
61
+ expect(errors.length).toBeGreaterThan(0);
62
+ expect(errors[0].message).toContain("type mismatch");
63
+ });
64
+ });
65
+
66
+ describe("void 제약", () => {
67
+ it("void 변수 금지", () => {
68
+ const errors = check("var x: void = println()");
69
+ expect(errors.length).toBeGreaterThan(0);
70
+ expect(errors[0].message).toContain("void");
71
+ });
72
+ });
73
+
74
+ describe("산술 연산", () => {
75
+ it("i32 + i32", () => {
76
+ const errors = check("fn f() -> i32 { return 1 + 2 }");
77
+ expect(errors.length).toBe(0);
78
+ });
79
+
80
+ it("f64 + f64", () => {
81
+ const errors = check("fn f() -> f64 { return 1.0 + 2.0 }");
82
+ expect(errors.length).toBe(0);
83
+ });
84
+
85
+ it("i32 + f64 불일치", () => {
86
+ const errors = check("fn f() -> i32 { return 1 + 1.0 }");
87
+ expect(errors.length).toBeGreaterThan(0);
88
+ });
89
+
90
+ it("string + string", () => {
91
+ const errors = check('fn f() -> string { return "a" + "b" }');
92
+ expect(errors.length).toBe(0);
93
+ });
94
+ });
95
+
96
+ describe("비교 연산", () => {
97
+ it("== → bool", () => {
98
+ const errors = check("fn f() -> bool { return 1 == 2 }");
99
+ expect(errors.length).toBe(0);
100
+ });
101
+
102
+ it("< → bool", () => {
103
+ const errors = check("fn f() -> bool { return 1 < 2 }");
104
+ expect(errors.length).toBe(0);
105
+ });
106
+ });
107
+
108
+ describe("논리 연산", () => {
109
+ it("&& bool", () => {
110
+ const errors = check("fn f() -> bool { return true && false }");
111
+ expect(errors.length).toBe(0);
112
+ });
113
+
114
+ it("&& 에 i32 사용", () => {
115
+ const errors = check("fn f() -> bool { return 1 && 2 }");
116
+ expect(errors.length).toBeGreaterThan(0);
117
+ expect(errors[0].message).toContain("requires bool");
118
+ });
119
+ });
120
+
121
+ describe("단항 연산", () => {
122
+ it("unary -", () => {
123
+ const errors = check("fn f() -> i32 { return -42 }");
124
+ expect(errors.length).toBe(0);
125
+ });
126
+
127
+ it("unary !", () => {
128
+ const errors = check("fn f() -> bool { return !true }");
129
+ expect(errors.length).toBe(0);
130
+ });
131
+
132
+ it("! 에 i32 사용", () => {
133
+ const errors = check("fn f() -> bool { return !42 }");
134
+ expect(errors.length).toBeGreaterThan(0);
135
+ expect(errors[0].message).toContain("requires bool");
136
+ });
137
+ });
138
+
139
+ describe("함수 검사", () => {
140
+ it("반환 타입 불일치", () => {
141
+ const errors = check('fn f() -> i32 { return "hello" }');
142
+ expect(errors.length).toBeGreaterThan(0);
143
+ expect(errors[0].message).toContain("return type mismatch");
144
+ });
145
+
146
+ it("인자 수 부족", () => {
147
+ const errors = check(
148
+ `fn add(a: i32, b: i32) -> i32 { return a + b }
149
+ add(1)`
150
+ );
151
+ expect(errors.length).toBeGreaterThan(0);
152
+ });
153
+
154
+ it("인자 타입 불일치", () => {
155
+ const errors = check(
156
+ `fn add(a: i32, b: i32) -> i32 { return a + b }
157
+ add(1, "two")`
158
+ );
159
+ expect(errors.length).toBeGreaterThan(0);
160
+ });
161
+
162
+ it("함수 전방참조", () => {
163
+ const errors = check(`
164
+ fn main() -> void { println(str(add(1, 2))) }
165
+ fn add(a: i32, b: i32) -> i32 { return a + b }
166
+ `);
167
+ expect(errors.length).toBe(0);
168
+ });
169
+
170
+ it("함수 중복 선언", () => {
171
+ const errors = check(`fn f() -> void { }
172
+ fn f() -> void { }`);
173
+ expect(errors.length).toBeGreaterThan(0);
174
+ });
175
+ });
176
+
177
+ describe("불변성", () => {
178
+ it("var 재할당 허용", () => {
179
+ const errors = check("var x = 1\nx = 2");
180
+ expect(errors.length).toBe(0);
181
+ });
182
+
183
+ it("let 재할당 금지", () => {
184
+ const errors = check("let x = 1\nx = 2");
185
+ expect(errors.length).toBeGreaterThan(0);
186
+ expect(errors[0].message).toContain("immutable");
187
+ });
188
+ });
189
+ });
@@ -0,0 +1,279 @@
1
+ // FreeLang v4 — TypeChecker 테스트
2
+
3
+ import { Lexer } from "./lexer";
4
+ import { Parser } from "./parser";
5
+ import { TypeChecker, CheckError } from "./checker";
6
+
7
+ function check(source: string): CheckError[] {
8
+ const { tokens, errors: lexErrors } = new Lexer(source).tokenize();
9
+ if (lexErrors.length > 0) throw new Error(`Lex: ${lexErrors[0].message}`);
10
+ const { program, errors: parseErrors } = new Parser(tokens).parse();
11
+ if (parseErrors.length > 0) throw new Error(`Parse: ${parseErrors[0].message}`);
12
+ return new TypeChecker().check(program);
13
+ }
14
+
15
+ function expectNoErrors(source: string, label: string) {
16
+ const errors = check(source);
17
+ if (errors.length > 0) {
18
+ console.error(` ❌ ${label}: ${errors.map((e) => e.message).join(", ")}`);
19
+ failed++;
20
+ } else {
21
+ console.log(` ✅ ${label}`);
22
+ passed++;
23
+ }
24
+ }
25
+
26
+ function expectError(source: string, pattern: string, label: string) {
27
+ const errors = check(source);
28
+ const found = errors.some((e) => e.message.includes(pattern));
29
+ if (found) {
30
+ console.log(` ✅ ${label}`);
31
+ passed++;
32
+ } else {
33
+ console.error(` ❌ ${label}: expected error "${pattern}", got [${errors.map((e) => e.message).join(", ")}]`);
34
+ failed++;
35
+ }
36
+ }
37
+
38
+ let passed = 0;
39
+ let failed = 0;
40
+
41
+ // ============================================================
42
+ // 1. 기본 타입 추론 (SPEC_06 Q3)
43
+ // ============================================================
44
+
45
+ console.log("=== 타입 추론 ===");
46
+
47
+ expectNoErrors("var x = 42", "var x = 42 (i32 추론)");
48
+ expectNoErrors("var x = 3.14", "var x = 3.14 (f64 추론)");
49
+ expectNoErrors('var x = "hello"', 'var x = "hello" (string 추론)');
50
+ expectNoErrors("var x = true", "var x = true (bool 추론)");
51
+
52
+ // 명시 타입 일치
53
+ expectNoErrors("var x: i32 = 42", "var x: i32 = 42");
54
+ expectNoErrors("var x: f64 = 3.14", "var x: f64 = 3.14");
55
+
56
+ // 명시 타입 불일치
57
+ expectError('var x: i32 = "hello"', "type mismatch", "i32 = string 불일치");
58
+ expectError("var x: bool = 42", "type mismatch", "bool = i32 불일치");
59
+
60
+ // ============================================================
61
+ // 2. void 변수 금지 (SPEC_06 Q9)
62
+ // ============================================================
63
+
64
+ console.log("=== void 제약 ===");
65
+
66
+ expectError("var x: void = println()", "void", "void 변수 금지");
67
+
68
+ // ============================================================
69
+ // 3. 산술 연산 타입 검사
70
+ // ============================================================
71
+
72
+ console.log("=== 산술 연산 ===");
73
+
74
+ expectNoErrors("fn f(): i32 { return 1 + 2 }", "i32 + i32");
75
+ expectNoErrors("fn f(): f64 { return 1.0 + 2.0 }", "f64 + f64");
76
+ expectError("fn f(): i32 { return 1 + 1.0 }", "type mismatch", "i32 + f64 불일치");
77
+
78
+ // 문자열 + 문자열 (SPEC_06)
79
+ expectNoErrors('fn f(): string { return "a" + "b" }', "string + string");
80
+
81
+ // ============================================================
82
+ // 4. 비교 연산 → bool
83
+ // ============================================================
84
+
85
+ console.log("=== 비교 연산 ===");
86
+
87
+ expectNoErrors("fn f(): bool { return 1 == 2 }", "== → bool");
88
+ expectNoErrors("fn f(): bool { return 1 < 2 }", "< → bool");
89
+
90
+ // ============================================================
91
+ // 5. 논리 연산 — bool 필요
92
+ // ============================================================
93
+
94
+ console.log("=== 논리 연산 ===");
95
+
96
+ expectNoErrors("fn f(): bool { return true && false }", "&& bool");
97
+ expectError("fn f(): bool { return 1 && 2 }", "requires bool", "&& 에 i32 사용");
98
+
99
+ // ============================================================
100
+ // 6. 단항 연산
101
+ // ============================================================
102
+
103
+ console.log("=== 단항 연산 ===");
104
+
105
+ expectNoErrors("fn f(): i32 { return -42 }", "unary -");
106
+ expectNoErrors("fn f(): bool { return !true }", "unary !");
107
+ expectError("fn f(): bool { return !42 }", "requires bool", "! 에 i32 사용");
108
+
109
+ // ============================================================
110
+ // 7. 함수 검사
111
+ // ============================================================
112
+
113
+ console.log("=== 함수 검사 ===");
114
+
115
+ // 반환 타입 불일치
116
+ expectError('fn f(): i32 { return "hello" }', "return type mismatch", "반환 타입 불일치");
117
+
118
+ // 인자 수 불일치
119
+ expectError(`fn add(a: i32, b: i32): i32 { return a + b }
120
+ add(1)`, "expects 2 arguments", "인자 수 부족");
121
+
122
+ // 인자 타입 불일치
123
+ expectError(`fn add(a: i32, b: i32): i32 { return a + b }
124
+ add(1, "two")`, "argument 2 type mismatch", "인자 타입 불일치");
125
+
126
+ // 전방참조 (SPEC_08 Q5)
127
+ expectNoErrors(`
128
+ fn main(): void { println(str(add(1, 2))) }
129
+ fn add(a: i32, b: i32): i32 { return a + b }
130
+ `, "함수 전방참조");
131
+
132
+ // 중복 함수 선언
133
+ expectError(`fn f(): void { }
134
+ fn f(): void { }`, "already declared", "함수 중복 선언");
135
+
136
+ // ============================================================
137
+ // 8. 변수 immutability (SPEC_07)
138
+ // ============================================================
139
+
140
+ console.log("=== 불변성 ===");
141
+
142
+ expectNoErrors("var x = 1\nx = 2", "var 재할당 허용");
143
+ expectError("let x = 1\nx = 2", "immutable", "let 재할당 금지");
144
+
145
+ // ============================================================
146
+ // 9. Move semantics (SPEC_07)
147
+ // ============================================================
148
+
149
+ console.log("=== Move ===");
150
+
151
+ // Move 타입 사용 후 재사용 — 함수 인자 전달
152
+ expectError(`
153
+ fn consume(arr: [i32]): void { }
154
+ var items: [i32] = [1, 2, 3]
155
+ consume(items)
156
+ println(length(items))
157
+ `, "moved value", "Move 후 사용 금지");
158
+
159
+ // 재할당으로 Move 복구 (SPEC_07 Q7)
160
+ expectNoErrors(`
161
+ fn consume(arr: [i32]): void { }
162
+ var items: [i32] = [1, 2, 3]
163
+ consume(items)
164
+ items = [4, 5, 6]
165
+ println(length(items))
166
+ `, "Move 후 재할당 복구");
167
+
168
+ // Copy 타입은 Move 안 됨
169
+ expectNoErrors(`
170
+ fn use_num(n: i32): void { }
171
+ var x = 42
172
+ use_num(x)
173
+ println(str(x))
174
+ `, "Copy 타입 이동 없음");
175
+
176
+ // ============================================================
177
+ // 10. 스코프 (SPEC_08)
178
+ // ============================================================
179
+
180
+ console.log("=== 스코프 ===");
181
+
182
+ // 미정의 변수
183
+ expectError("println(str(x))", "undefined variable", "미정의 변수");
184
+
185
+ // 섀도잉 (SPEC_08 Q4)
186
+ expectNoErrors(`var x = 42
187
+ var x = "hello"`, "섀도잉 허용");
188
+
189
+ // ============================================================
190
+ // 11. if 조건 — bool 필수
191
+ // ============================================================
192
+
193
+ console.log("=== if 조건 ===");
194
+
195
+ expectError("if 42 { }", "must be bool", "if 조건 non-bool");
196
+ expectNoErrors('if true { println("yes") }', "if true");
197
+
198
+ // ============================================================
199
+ // 12. for...in — array 필수
200
+ // ============================================================
201
+
202
+ console.log("=== for...in ===");
203
+
204
+ expectNoErrors("for x in [1, 2, 3] { println(str(x)) }", "for in array");
205
+ expectError("for x in 42 { }", "requires array", "for in non-array");
206
+
207
+ // ============================================================
208
+ // 13. 배열 원소 타입 일관성
209
+ // ============================================================
210
+
211
+ console.log("=== 배열 ===");
212
+
213
+ expectNoErrors("var arr = [1, 2, 3]", "동종 배열");
214
+ expectError('var arr = [1, "two", 3]', "array element type mismatch", "이종 배열");
215
+
216
+ // ============================================================
217
+ // 14. 구조체 (구조적 타입)
218
+ // ============================================================
219
+
220
+ console.log("=== 구조체 ===");
221
+
222
+ expectNoErrors('var p = { x: 1, y: 2 }', "구조체 리터럴");
223
+
224
+ // ============================================================
225
+ // 15. 내장 함수
226
+ // ============================================================
227
+
228
+ console.log("=== 내장 함수 ===");
229
+
230
+ expectNoErrors('println("hello")', "println");
231
+ expectNoErrors("var r = range(0, 10)", "range → [i32]");
232
+ expectNoErrors("var n = length([1, 2, 3])", "length → i32");
233
+
234
+ // ============================================================
235
+ // 16. return 밖에서 사용
236
+ // ============================================================
237
+
238
+ console.log("=== return 제약 ===");
239
+
240
+ expectError("return 42", "return outside function", "함수 밖 return");
241
+
242
+ // void 함수에서 return value
243
+ expectError("fn f(): void { return 42 }", "return type mismatch", "void 함수에서 값 반환");
244
+
245
+ // ============================================================
246
+ // 17. 통합 — 실제 프로그램
247
+ // ============================================================
248
+
249
+ console.log("=== 통합 테스트 ===");
250
+
251
+ expectNoErrors(`
252
+ fn factorial(n: i32): i32 {
253
+ if n <= 1 {
254
+ return 1
255
+ }
256
+ return n * factorial(n + -1)
257
+ }
258
+ var result = factorial(5)
259
+ println(str(result))
260
+ `, "factorial 프로그램");
261
+
262
+ expectNoErrors(`
263
+ fn sum(arr: [i32]): i32 {
264
+ var total: i32 = 0
265
+ for x in arr {
266
+ total = total + x
267
+ }
268
+ return total
269
+ }
270
+ var nums = [1, 2, 3, 4, 5]
271
+ println(str(sum(nums)))
272
+ `, "sum 프로그램");
273
+
274
+ // ============================================================
275
+ // 결과
276
+ // ============================================================
277
+
278
+ console.log(`\n=== 결과: ${passed} passed, ${failed} failed ===`);
279
+ if (failed > 0) process.exit(1);