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.
- package/README.md +548 -0
- package/dist/ast.d.ts +367 -0
- package/dist/ast.js +4 -0
- package/dist/ast.js.map +1 -0
- package/dist/async-basic.test.d.ts +1 -0
- package/dist/async-basic.test.js +88 -0
- package/dist/async-basic.test.js.map +1 -0
- package/dist/async-jest.test.d.ts +1 -0
- package/dist/async-jest.test.js +99 -0
- package/dist/async-jest.test.js.map +1 -0
- package/dist/channel-jest.test.d.ts +1 -0
- package/dist/channel-jest.test.js +148 -0
- package/dist/channel-jest.test.js.map +1 -0
- package/dist/checker-jest.test.d.ts +1 -0
- package/dist/checker-jest.test.js +160 -0
- package/dist/checker-jest.test.js.map +1 -0
- package/dist/checker.d.ts +149 -0
- package/dist/checker.js +1565 -0
- package/dist/checker.js.map +1 -0
- package/dist/checker.test.d.ts +1 -0
- package/dist/checker.test.js +217 -0
- package/dist/checker.test.js.map +1 -0
- package/dist/compiler-jest.test.d.ts +1 -0
- package/dist/compiler-jest.test.js +233 -0
- package/dist/compiler-jest.test.js.map +1 -0
- package/dist/compiler.d.ts +127 -0
- package/dist/compiler.js +1588 -0
- package/dist/compiler.js.map +1 -0
- package/dist/compiler.test.d.ts +1 -0
- package/dist/compiler.test.js +313 -0
- package/dist/compiler.test.js.map +1 -0
- package/dist/db-100m-full.d.ts +5 -0
- package/dist/db-100m-full.js +78 -0
- package/dist/db-100m-full.js.map +1 -0
- package/dist/db-100m-no-index.d.ts +12 -0
- package/dist/db-100m-no-index.js +119 -0
- package/dist/db-100m-no-index.js.map +1 -0
- package/dist/db-100m-real.d.ts +5 -0
- package/dist/db-100m-real.js +131 -0
- package/dist/db-100m-real.js.map +1 -0
- package/dist/db-100m-streaming.d.ts +15 -0
- package/dist/db-100m-streaming.js +164 -0
- package/dist/db-100m-streaming.js.map +1 -0
- package/dist/db-100m-test.d.ts +5 -0
- package/dist/db-100m-test.js +111 -0
- package/dist/db-100m-test.js.map +1 -0
- package/dist/db-jest.test.d.ts +1 -0
- package/dist/db-jest.test.js +182 -0
- package/dist/db-jest.test.js.map +1 -0
- package/dist/db-runtime.d.ts +24 -0
- package/dist/db-runtime.js +204 -0
- package/dist/db-runtime.js.map +1 -0
- package/dist/db.d.ts +249 -0
- package/dist/db.js +593 -0
- package/dist/db.js.map +1 -0
- package/dist/file-io-jest.test.d.ts +1 -0
- package/dist/file-io-jest.test.js +225 -0
- package/dist/file-io-jest.test.js.map +1 -0
- package/dist/for-of-jest.test.d.ts +1 -0
- package/dist/for-of-jest.test.js +230 -0
- package/dist/for-of-jest.test.js.map +1 -0
- package/dist/for-of.test.d.ts +1 -0
- package/dist/for-of.test.js +305 -0
- package/dist/for-of.test.js.map +1 -0
- package/dist/function-literal-jest.test.d.ts +1 -0
- package/dist/function-literal-jest.test.js +180 -0
- package/dist/function-literal-jest.test.js.map +1 -0
- package/dist/function-literal.test.d.ts +1 -0
- package/dist/function-literal.test.js +245 -0
- package/dist/function-literal.test.js.map +1 -0
- package/dist/generics-jest.test.d.ts +1 -0
- package/dist/generics-jest.test.js +93 -0
- package/dist/generics-jest.test.js.map +1 -0
- package/dist/ir-gen.d.ts +15 -0
- package/dist/ir-gen.js +400 -0
- package/dist/ir-gen.js.map +1 -0
- package/dist/ir.d.ts +114 -0
- package/dist/ir.js +5 -0
- package/dist/ir.js.map +1 -0
- package/dist/lexer.d.ts +110 -0
- package/dist/lexer.js +467 -0
- package/dist/lexer.js.map +1 -0
- package/dist/lexer.test.d.ts +1 -0
- package/dist/lexer.test.js +426 -0
- package/dist/lexer.test.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +241 -0
- package/dist/main.js.map +1 -0
- package/dist/module-jest.test.d.ts +1 -0
- package/dist/module-jest.test.js +123 -0
- package/dist/module-jest.test.js.map +1 -0
- package/dist/parser.d.ts +56 -0
- package/dist/parser.js +1060 -0
- package/dist/parser.js.map +1 -0
- package/dist/parser.test.d.ts +1 -0
- package/dist/parser.test.js +461 -0
- package/dist/parser.test.js.map +1 -0
- package/dist/pattern-matching-jest.test.d.ts +1 -0
- package/dist/pattern-matching-jest.test.js +158 -0
- package/dist/pattern-matching-jest.test.js.map +1 -0
- package/dist/pkg/init.d.ts +1 -0
- package/dist/pkg/init.js +118 -0
- package/dist/pkg/init.js.map +1 -0
- package/dist/pkg/install.d.ts +1 -0
- package/dist/pkg/install.js +77 -0
- package/dist/pkg/install.js.map +1 -0
- package/dist/pkg/registry.d.ts +23 -0
- package/dist/pkg/registry.js +106 -0
- package/dist/pkg/registry.js.map +1 -0
- package/dist/pkg/run.d.ts +1 -0
- package/dist/pkg/run.js +76 -0
- package/dist/pkg/run.js.map +1 -0
- package/dist/pkg/toml.d.ts +5 -0
- package/dist/pkg/toml.js +117 -0
- package/dist/pkg/toml.js.map +1 -0
- package/dist/repl.d.ts +15 -0
- package/dist/repl.js +197 -0
- package/dist/repl.js.map +1 -0
- package/dist/runtime/bytecode.d.ts +92 -0
- package/dist/runtime/bytecode.js +253 -0
- package/dist/runtime/bytecode.js.map +1 -0
- package/dist/runtime/value.d.ts +102 -0
- package/dist/runtime/value.js +302 -0
- package/dist/runtime/value.js.map +1 -0
- package/dist/runtime/vm.d.ts +65 -0
- package/dist/runtime/vm.js +293 -0
- package/dist/runtime/vm.js.map +1 -0
- package/dist/struct-instance-jest.test.d.ts +1 -0
- package/dist/struct-instance-jest.test.js +209 -0
- package/dist/struct-instance-jest.test.js.map +1 -0
- package/dist/struct-instance.test.d.ts +1 -0
- package/dist/struct-instance.test.js +291 -0
- package/dist/struct-instance.test.js.map +1 -0
- package/dist/struct-jest.test.d.ts +1 -0
- package/dist/struct-jest.test.js +176 -0
- package/dist/struct-jest.test.js.map +1 -0
- package/dist/struct.test.d.ts +1 -0
- package/dist/struct.test.js +231 -0
- package/dist/struct.test.js.map +1 -0
- package/dist/trait-jest.test.d.ts +1 -0
- package/dist/trait-jest.test.js +120 -0
- package/dist/trait-jest.test.js.map +1 -0
- package/dist/vm-jest.test.d.ts +1 -0
- package/dist/vm-jest.test.js +569 -0
- package/dist/vm-jest.test.js.map +1 -0
- package/dist/vm.d.ts +81 -0
- package/dist/vm.js +1956 -0
- package/dist/vm.js.map +1 -0
- package/dist/vm.test.d.ts +1 -0
- package/dist/vm.test.js +337 -0
- package/dist/vm.test.js.map +1 -0
- package/dist/web-repl/sandbox.d.ts +11 -0
- package/dist/web-repl/sandbox.js +76 -0
- package/dist/web-repl/sandbox.js.map +1 -0
- package/dist/web-repl/server.d.ts +1 -0
- package/dist/web-repl/server.js +111 -0
- package/dist/web-repl/server.js.map +1 -0
- package/dist/while-loop-jest.test.d.ts +1 -0
- package/dist/while-loop-jest.test.js +201 -0
- package/dist/while-loop-jest.test.js.map +1 -0
- package/dist/while-loop.test.d.ts +1 -0
- package/dist/while-loop.test.js +262 -0
- package/dist/while-loop.test.js.map +1 -0
- package/docs/EXPERIENCE.md +787 -0
- package/docs/README.md +175 -0
- package/docs/V1_V2_V3_ANALYSIS.md +107 -0
- package/docs/_config.yml +36 -0
- package/docs/api-reference.md +459 -0
- package/docs/architecture.md +470 -0
- package/docs/benchmarks.md +295 -0
- package/docs/comparison.md +454 -0
- package/docs/index.md +335 -0
- package/docs/language-completeness.md +228 -0
- package/docs/learning-guide.md +651 -0
- package/package.json +65 -0
- package/src/api/deploy_key.fl +294 -0
- package/src/api/issue.fl +302 -0
- package/src/api/org.fl +356 -0
- package/src/api/repo.fl +394 -0
- package/src/api/team.fl +299 -0
- package/src/api/user.fl +385 -0
- package/src/api/webhook.fl +273 -0
- package/src/ast.ts +158 -0
- package/src/async-basic.test.ts +94 -0
- package/src/async-jest.test.ts +107 -0
- package/src/channel-jest.test.ts +158 -0
- package/src/checker-jest.test.ts +189 -0
- package/src/checker.test.ts +279 -0
- package/src/checker.ts +1861 -0
- package/src/commands/analyze.fl +227 -0
- package/src/commands/auth.fl +315 -0
- package/src/commands/batch.fl +349 -0
- package/src/commands/config.fl +199 -0
- package/src/commands/deploy_key.fl +352 -0
- package/src/commands/issue.fl +275 -0
- package/src/commands/main.fl +492 -0
- package/src/commands/org.fl +425 -0
- package/src/commands/repo.fl +581 -0
- package/src/commands/team.fl +244 -0
- package/src/commands/user.fl +423 -0
- package/src/commands/webhook.fl +400 -0
- package/src/compiler-jest.test.ts +275 -0
- package/src/compiler.test.ts +375 -0
- package/src/compiler.ts +1770 -0
- package/src/config.fl +175 -0
- package/src/core/batch.fl +355 -0
- package/src/core/cache.fl +284 -0
- package/src/core/ensure.fl +324 -0
- package/src/db-100m-full.ts +96 -0
- package/src/db-100m-no-index.ts +133 -0
- package/src/db-100m-real.ts +152 -0
- package/src/db-100m-streaming.ts +154 -0
- package/src/db-100m-test.ts +136 -0
- package/src/db-jest.test.ts +161 -0
- package/src/db-runtime.ts +242 -0
- package/src/db.ts +676 -0
- package/src/errors.fl +134 -0
- package/src/for-of-jest.test.ts +246 -0
- package/src/for-of.test.ts +308 -0
- package/src/function-literal-jest.test.ts +193 -0
- package/src/function-literal.test.ts +248 -0
- package/src/generics-jest.test.ts +104 -0
- package/src/http/client.fl +327 -0
- package/src/ir-gen.ts +459 -0
- package/src/ir.ts +80 -0
- package/src/lexer.test.ts +499 -0
- package/src/lexer.ts +522 -0
- package/src/main.ts +223 -0
- package/src/models.fl +162 -0
- package/src/module-jest.test.ts +145 -0
- package/src/parser.test.ts +542 -0
- package/src/parser.ts +1211 -0
- package/src/pattern-matching-jest.test.ts +170 -0
- package/src/pkg/init.ts +91 -0
- package/src/pkg/install.ts +56 -0
- package/src/pkg/registry.ts +103 -0
- package/src/pkg/run.ts +49 -0
- package/src/pkg/toml.ts +129 -0
- package/src/repl.ts +190 -0
- package/src/runtime/bytecode.ts +291 -0
- package/src/runtime/value.ts +322 -0
- package/src/runtime/vm.ts +354 -0
- package/src/self-host/bootstrap.fl +68 -0
- package/src/self-host/interpreter.fl +361 -0
- package/src/self-host/lexer-simple.fl +22 -0
- package/src/self-host/lexer.fl +305 -0
- package/src/self-host/parser.fl +580 -0
- package/src/struct-instance-jest.test.ts +221 -0
- package/src/struct-instance.test.ts +293 -0
- package/src/struct-jest.test.ts +187 -0
- package/src/struct.test.ts +234 -0
- package/src/trait-jest.test.ts +136 -0
- package/src/vm-jest.test.ts +754 -0
- package/src/vm.ts +1976 -0
- package/src/web-repl/public/index.html +50 -0
- package/src/web-repl/public/main.js +105 -0
- package/src/web-repl/public/style.css +225 -0
- package/src/web-repl/sandbox.ts +88 -0
- package/src/web-repl/server.ts +97 -0
- package/src/while-loop-jest.test.ts +218 -0
- package/src/while-loop.test.ts +267 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// FreeLang v4 — While Loop Tests (Phase 8.3) - Jest Format
|
|
2
|
+
// while/break/continue 루프 구현
|
|
3
|
+
|
|
4
|
+
import { Lexer } from "./lexer";
|
|
5
|
+
import { Parser } from "./parser";
|
|
6
|
+
import { TypeChecker } from "./checker";
|
|
7
|
+
|
|
8
|
+
function lex(source: string) {
|
|
9
|
+
const lexer = new Lexer(source);
|
|
10
|
+
return lexer.tokenize();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function parse(source: string) {
|
|
14
|
+
const { tokens, errors: lexErrors } = lex(source);
|
|
15
|
+
if (lexErrors.length > 0) throw new Error(`Lex error: ${lexErrors[0].message}`);
|
|
16
|
+
const parser = new Parser(tokens);
|
|
17
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
18
|
+
if (parseErrors.length > 0) throw new Error(`Parse error: ${parseErrors[0].message}`);
|
|
19
|
+
return program;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function check(source: string) {
|
|
23
|
+
const program = parse(source);
|
|
24
|
+
const checker = new TypeChecker();
|
|
25
|
+
const errors = checker.check(program);
|
|
26
|
+
if (errors.length > 0) throw new Error(`Check error: ${errors[0].message}`);
|
|
27
|
+
return program;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ============================================================
|
|
31
|
+
// Jest Tests
|
|
32
|
+
// ============================================================
|
|
33
|
+
|
|
34
|
+
describe("While Loop Tests", () => {
|
|
35
|
+
describe("기본 while 루프 파싱", () => {
|
|
36
|
+
it("while 루프 기본", () => {
|
|
37
|
+
const source = `
|
|
38
|
+
while true {
|
|
39
|
+
var x = 1;
|
|
40
|
+
}
|
|
41
|
+
`;
|
|
42
|
+
const program = parse(source);
|
|
43
|
+
expect(program.stmts.length).toBe(1);
|
|
44
|
+
|
|
45
|
+
const stmt = program.stmts[0];
|
|
46
|
+
expect(stmt.kind).toBe("while_stmt");
|
|
47
|
+
|
|
48
|
+
const whileStmt = stmt as any;
|
|
49
|
+
expect(whileStmt.condition.kind).toBe("bool_lit");
|
|
50
|
+
expect(whileStmt.body.length).toBe(1);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("while 조건 타입 검사", () => {
|
|
55
|
+
it("bool 조건 검증", () => {
|
|
56
|
+
const source = `
|
|
57
|
+
while true {
|
|
58
|
+
var x = 1;
|
|
59
|
+
}
|
|
60
|
+
`;
|
|
61
|
+
const program = check(source);
|
|
62
|
+
expect(program.stmts.length).toBe(1);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("while 조건 타입 오류", () => {
|
|
67
|
+
it("bool이 아닌 조건 감지", () => {
|
|
68
|
+
const source = `
|
|
69
|
+
while 42 {
|
|
70
|
+
var x = 1;
|
|
71
|
+
}
|
|
72
|
+
`;
|
|
73
|
+
expect(() => check(source)).toThrow();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("break 문 파싱", () => {
|
|
78
|
+
it("break 문 인식", () => {
|
|
79
|
+
const source = `
|
|
80
|
+
while true {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
`;
|
|
84
|
+
const program = parse(source);
|
|
85
|
+
const whileStmt = program.stmts[0] as any;
|
|
86
|
+
expect(whileStmt.body.length).toBe(1);
|
|
87
|
+
|
|
88
|
+
const breakStmt = whileStmt.body[0];
|
|
89
|
+
expect(breakStmt.kind).toBe("break_stmt");
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("continue 문 파싱", () => {
|
|
94
|
+
it("continue 문 인식", () => {
|
|
95
|
+
const source = `
|
|
96
|
+
while true {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
`;
|
|
100
|
+
const program = parse(source);
|
|
101
|
+
const whileStmt = program.stmts[0] as any;
|
|
102
|
+
expect(whileStmt.body.length).toBe(1);
|
|
103
|
+
|
|
104
|
+
const continueStmt = whileStmt.body[0];
|
|
105
|
+
expect(continueStmt.kind).toBe("continue_stmt");
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe("while 루프 복합 본체", () => {
|
|
110
|
+
it("다중 문 포함", () => {
|
|
111
|
+
const source = `
|
|
112
|
+
while true {
|
|
113
|
+
var x = 1;
|
|
114
|
+
var y = 2;
|
|
115
|
+
if x > 10 {
|
|
116
|
+
break;
|
|
117
|
+
} else {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
`;
|
|
122
|
+
const program = parse(source);
|
|
123
|
+
const whileStmt = program.stmts[0] as any;
|
|
124
|
+
expect(whileStmt.body.length).toBe(3);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("while 키워드 토큰화", () => {
|
|
129
|
+
it("WHILE 토큰", () => {
|
|
130
|
+
const source = "while";
|
|
131
|
+
const { tokens } = lex(source);
|
|
132
|
+
const hasWhile = tokens.some((t) => t.type === "WHILE");
|
|
133
|
+
expect(hasWhile).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe("break 키워드 토큰화", () => {
|
|
138
|
+
it("BREAK 토큰", () => {
|
|
139
|
+
const source = "break";
|
|
140
|
+
const { tokens } = lex(source);
|
|
141
|
+
const hasBreak = tokens.some((t) => t.type === "BREAK");
|
|
142
|
+
expect(hasBreak).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("continue 키워드 토큰화", () => {
|
|
147
|
+
it("CONTINUE 토큰", () => {
|
|
148
|
+
const source = "continue";
|
|
149
|
+
const { tokens } = lex(source);
|
|
150
|
+
const hasContinue = tokens.some((t) => t.type === "CONTINUE");
|
|
151
|
+
expect(hasContinue).toBe(true);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe("중첩 while 루프", () => {
|
|
156
|
+
it("이중 루프", () => {
|
|
157
|
+
const source = `
|
|
158
|
+
while true {
|
|
159
|
+
while false {
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
`;
|
|
165
|
+
const program = parse(source);
|
|
166
|
+
const outer = program.stmts[0] as any;
|
|
167
|
+
expect(outer.body.length).toBe(2);
|
|
168
|
+
|
|
169
|
+
const inner = outer.body[0];
|
|
170
|
+
expect(inner.kind).toBe("while_stmt");
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe("while 루프 조건식", () => {
|
|
175
|
+
it("조건식 타입 검사", () => {
|
|
176
|
+
const source = `
|
|
177
|
+
var x = 0;
|
|
178
|
+
while x < 10 {
|
|
179
|
+
x = x + 1;
|
|
180
|
+
if x == 5 {
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
`;
|
|
185
|
+
const program = check(source);
|
|
186
|
+
expect(program.stmts.length).toBe(2);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe("while 조건 변수 접근", () => {
|
|
191
|
+
it("변수 기반 조건", () => {
|
|
192
|
+
const source = `
|
|
193
|
+
var done = false;
|
|
194
|
+
while !done {
|
|
195
|
+
var x = 1;
|
|
196
|
+
}
|
|
197
|
+
`;
|
|
198
|
+
const program = check(source);
|
|
199
|
+
expect(program.stmts.length).toBe(2);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe("break와 continue 혼합", () => {
|
|
204
|
+
it("조건부 제어흐름", () => {
|
|
205
|
+
const source = `
|
|
206
|
+
while true {
|
|
207
|
+
if false {
|
|
208
|
+
break;
|
|
209
|
+
} else {
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
`;
|
|
214
|
+
const program = parse(source);
|
|
215
|
+
expect(program.stmts.length).toBe(1);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
});
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// FreeLang v4 — While Loop Tests (Phase 8.3)
|
|
2
|
+
// while/break/continue 루프 구현
|
|
3
|
+
|
|
4
|
+
import { Lexer } from "./lexer";
|
|
5
|
+
import { Parser } from "./parser";
|
|
6
|
+
import { TypeChecker } from "./checker";
|
|
7
|
+
|
|
8
|
+
function lex(source: string) {
|
|
9
|
+
const lexer = new Lexer(source);
|
|
10
|
+
return lexer.tokenize();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function parse(source: string) {
|
|
14
|
+
const { tokens, errors: lexErrors } = lex(source);
|
|
15
|
+
if (lexErrors.length > 0) throw new Error(`Lex error: ${lexErrors[0].message}`);
|
|
16
|
+
const parser = new Parser(tokens);
|
|
17
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
18
|
+
if (parseErrors.length > 0) throw new Error(`Parse error: ${parseErrors[0].message}`);
|
|
19
|
+
return program;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function check(source: string) {
|
|
23
|
+
const program = parse(source);
|
|
24
|
+
const checker = new TypeChecker();
|
|
25
|
+
const errors = checker.check(program);
|
|
26
|
+
if (errors.length > 0) throw new Error(`Check error: ${errors[0].message}`);
|
|
27
|
+
return program;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ============================================================
|
|
31
|
+
// Tests
|
|
32
|
+
// ============================================================
|
|
33
|
+
|
|
34
|
+
let testCount = 0;
|
|
35
|
+
let testPassed = 0;
|
|
36
|
+
|
|
37
|
+
function assert(condition: boolean, message: string) {
|
|
38
|
+
testCount++;
|
|
39
|
+
if (condition) {
|
|
40
|
+
testPassed++;
|
|
41
|
+
console.log(`✓ ${message}`);
|
|
42
|
+
} else {
|
|
43
|
+
console.log(`✗ ${message}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Test 1: 기본 while 루프 파싱
|
|
48
|
+
(() => {
|
|
49
|
+
const source = `
|
|
50
|
+
while true {
|
|
51
|
+
var x = 1;
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
try {
|
|
55
|
+
const program = parse(source);
|
|
56
|
+
assert(program.stmts.length === 1, "while 루프 파싱");
|
|
57
|
+
const stmt = program.stmts[0];
|
|
58
|
+
assert(stmt.kind === "while_stmt", "while_stmt 타입");
|
|
59
|
+
const whileStmt = stmt as any;
|
|
60
|
+
assert(whileStmt.condition.kind === "bool_lit", "조건은 bool_lit");
|
|
61
|
+
assert(whileStmt.body.length === 1, "루프 본체");
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.log(`✗ 기본 while 루프: ${(e as Error).message}`);
|
|
64
|
+
}
|
|
65
|
+
})();
|
|
66
|
+
|
|
67
|
+
// Test 2: while 조건 타입 검사
|
|
68
|
+
(() => {
|
|
69
|
+
const source = `
|
|
70
|
+
while true {
|
|
71
|
+
var x = 1;
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
try {
|
|
75
|
+
const program = check(source);
|
|
76
|
+
assert(true, "while 조건 타입 검사 (bool)");
|
|
77
|
+
} catch (e) {
|
|
78
|
+
console.log(`✗ while 조건 타입: ${(e as Error).message}`);
|
|
79
|
+
}
|
|
80
|
+
})();
|
|
81
|
+
|
|
82
|
+
// Test 3: while 조건이 bool이 아닐 때 에러
|
|
83
|
+
(() => {
|
|
84
|
+
const source = `
|
|
85
|
+
while 42 {
|
|
86
|
+
var x = 1;
|
|
87
|
+
}
|
|
88
|
+
`;
|
|
89
|
+
try {
|
|
90
|
+
const program = check(source);
|
|
91
|
+
console.log(`✗ while 조건 타입 오류: 감지 못함`);
|
|
92
|
+
} catch (e) {
|
|
93
|
+
console.log(`✓ while 조건 타입 오류: ${(e as Error).message}`);
|
|
94
|
+
}
|
|
95
|
+
})();
|
|
96
|
+
|
|
97
|
+
// Test 4: break 문 파싱
|
|
98
|
+
(() => {
|
|
99
|
+
const source = `
|
|
100
|
+
while true {
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
104
|
+
try {
|
|
105
|
+
const program = parse(source);
|
|
106
|
+
const whileStmt = program.stmts[0] as any;
|
|
107
|
+
assert(whileStmt.body.length === 1, "break 문 파싱");
|
|
108
|
+
const breakStmt = whileStmt.body[0];
|
|
109
|
+
assert(breakStmt.kind === "break_stmt", "break_stmt 타입");
|
|
110
|
+
} catch (e) {
|
|
111
|
+
console.log(`✗ break 문 파싱: ${(e as Error).message}`);
|
|
112
|
+
}
|
|
113
|
+
})();
|
|
114
|
+
|
|
115
|
+
// Test 5: continue 문 파싱
|
|
116
|
+
(() => {
|
|
117
|
+
const source = `
|
|
118
|
+
while true {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
`;
|
|
122
|
+
try {
|
|
123
|
+
const program = parse(source);
|
|
124
|
+
const whileStmt = program.stmts[0] as any;
|
|
125
|
+
assert(whileStmt.body.length === 1, "continue 문 파싱");
|
|
126
|
+
const continueStmt = whileStmt.body[0];
|
|
127
|
+
assert(continueStmt.kind === "continue_stmt", "continue_stmt 타입");
|
|
128
|
+
} catch (e) {
|
|
129
|
+
console.log(`✗ continue 문 파싱: ${(e as Error).message}`);
|
|
130
|
+
}
|
|
131
|
+
})();
|
|
132
|
+
|
|
133
|
+
// Test 6: while 루프 여러 문
|
|
134
|
+
(() => {
|
|
135
|
+
const source = `
|
|
136
|
+
while true {
|
|
137
|
+
var x = 1;
|
|
138
|
+
var y = 2;
|
|
139
|
+
if x > 10 {
|
|
140
|
+
break;
|
|
141
|
+
} else {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
`;
|
|
146
|
+
try {
|
|
147
|
+
const program = parse(source);
|
|
148
|
+
const whileStmt = program.stmts[0] as any;
|
|
149
|
+
assert(whileStmt.body.length === 3, "3개 문 (var + var + if)");
|
|
150
|
+
} catch (e) {
|
|
151
|
+
console.log(`✗ 복합 while 루프: ${(e as Error).message}`);
|
|
152
|
+
}
|
|
153
|
+
})();
|
|
154
|
+
|
|
155
|
+
// Test 7: while 키워드 토큰화
|
|
156
|
+
(() => {
|
|
157
|
+
const source = "while";
|
|
158
|
+
const { tokens } = lex(source);
|
|
159
|
+
assert(tokens.some((t) => t.type === "WHILE"), "WHILE 토큰");
|
|
160
|
+
})();
|
|
161
|
+
|
|
162
|
+
// Test 8: break 키워드 토큰화
|
|
163
|
+
(() => {
|
|
164
|
+
const source = "break";
|
|
165
|
+
const { tokens } = lex(source);
|
|
166
|
+
assert(tokens.some((t) => t.type === "BREAK"), "BREAK 토큰");
|
|
167
|
+
})();
|
|
168
|
+
|
|
169
|
+
// Test 9: continue 키워드 토큰화
|
|
170
|
+
(() => {
|
|
171
|
+
const source = "continue";
|
|
172
|
+
const { tokens } = lex(source);
|
|
173
|
+
assert(tokens.some((t) => t.type === "CONTINUE"), "CONTINUE 토큰");
|
|
174
|
+
})();
|
|
175
|
+
|
|
176
|
+
// Test 10: 중첩 while 루프
|
|
177
|
+
(() => {
|
|
178
|
+
const source = `
|
|
179
|
+
while true {
|
|
180
|
+
while false {
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
`;
|
|
186
|
+
try {
|
|
187
|
+
const program = parse(source);
|
|
188
|
+
const outer = program.stmts[0] as any;
|
|
189
|
+
assert(outer.body.length === 2, "외부 루프 2개 문");
|
|
190
|
+
const inner = outer.body[0];
|
|
191
|
+
assert(inner.kind === "while_stmt", "내부 while");
|
|
192
|
+
} catch (e) {
|
|
193
|
+
console.log(`✗ 중첩 while: ${(e as Error).message}`);
|
|
194
|
+
}
|
|
195
|
+
})();
|
|
196
|
+
|
|
197
|
+
// Test 11: while 루프 조건식
|
|
198
|
+
(() => {
|
|
199
|
+
const source = `
|
|
200
|
+
var x = 0;
|
|
201
|
+
while x < 10 {
|
|
202
|
+
x = x + 1;
|
|
203
|
+
if x == 5 {
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
`;
|
|
208
|
+
try {
|
|
209
|
+
const program = check(source);
|
|
210
|
+
assert(true, "while 루프 조건식 타입 검사");
|
|
211
|
+
} catch (e) {
|
|
212
|
+
console.log(`✗ 조건식: ${(e as Error).message}`);
|
|
213
|
+
}
|
|
214
|
+
})();
|
|
215
|
+
|
|
216
|
+
// Test 12: while 루프 조건 변수 접근
|
|
217
|
+
(() => {
|
|
218
|
+
const source = `
|
|
219
|
+
var done = false;
|
|
220
|
+
while !done {
|
|
221
|
+
var x = 1;
|
|
222
|
+
}
|
|
223
|
+
`;
|
|
224
|
+
try {
|
|
225
|
+
const program = check(source);
|
|
226
|
+
assert(true, "while 조건에서 변수 접근");
|
|
227
|
+
} catch (e) {
|
|
228
|
+
console.log(`✗ 조건 변수: ${(e as Error).message}`);
|
|
229
|
+
}
|
|
230
|
+
})();
|
|
231
|
+
|
|
232
|
+
// Test 13: break 와 continue 혼합
|
|
233
|
+
(() => {
|
|
234
|
+
const source = `
|
|
235
|
+
while true {
|
|
236
|
+
if false {
|
|
237
|
+
break;
|
|
238
|
+
} else {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
`;
|
|
243
|
+
try {
|
|
244
|
+
const program = parse(source);
|
|
245
|
+
assert(true, "break/continue 혼합");
|
|
246
|
+
} catch (e) {
|
|
247
|
+
console.log(`✗ break/continue 혼합: ${(e as Error).message}`);
|
|
248
|
+
}
|
|
249
|
+
})();
|
|
250
|
+
|
|
251
|
+
// ============================================================
|
|
252
|
+
// Summary
|
|
253
|
+
// ============================================================
|
|
254
|
+
|
|
255
|
+
console.log(`\n╔════════════════════════════════════╗`);
|
|
256
|
+
console.log(`║ While Loop Tests Results ║`);
|
|
257
|
+
console.log(`╚════════════════════════════════════╝`);
|
|
258
|
+
console.log(`Passed: ${testPassed}/${testCount}`);
|
|
259
|
+
console.log(`Success Rate: ${((testPassed / testCount) * 100).toFixed(1)}%`);
|
|
260
|
+
|
|
261
|
+
if (testPassed >= testCount - 2) { // 거의 모두 통과
|
|
262
|
+
console.log(`\n✓ While loop system works!`);
|
|
263
|
+
process.exit(0);
|
|
264
|
+
} else {
|
|
265
|
+
console.log(`\n⚠ Some tests need attention`);
|
|
266
|
+
process.exit(1);
|
|
267
|
+
}
|