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,234 @@
|
|
|
1
|
+
// FreeLang v4 — Struct System Tests (Phase 8.1)
|
|
2
|
+
// struct 선언, 인스턴스 생성, 필드 접근
|
|
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: struct 선언 파싱
|
|
48
|
+
(() => {
|
|
49
|
+
const source = `
|
|
50
|
+
struct Person {
|
|
51
|
+
name: string,
|
|
52
|
+
age: i32
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
try {
|
|
56
|
+
const program = parse(source);
|
|
57
|
+
assert(program.stmts.length === 1, "struct 선언 파싱");
|
|
58
|
+
const stmt = program.stmts[0];
|
|
59
|
+
assert(stmt.kind === "struct_decl", "stmt kind is struct_decl");
|
|
60
|
+
const structStmt = stmt as any;
|
|
61
|
+
assert(structStmt.name === "Person", "struct name is Person");
|
|
62
|
+
assert(structStmt.fields.length === 2, "struct has 2 fields");
|
|
63
|
+
assert(structStmt.fields[0].name === "name", "첫 번째 필드 이름");
|
|
64
|
+
assert(structStmt.fields[0].type.kind === "string", "첫 번째 필드 타입");
|
|
65
|
+
assert(structStmt.fields[1].name === "age", "두 번째 필드 이름");
|
|
66
|
+
assert(structStmt.fields[1].type.kind === "i32", "두 번째 필드 타입");
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.log(`✗ struct 선언 파싱: ${(e as Error).message}`);
|
|
69
|
+
}
|
|
70
|
+
})();
|
|
71
|
+
|
|
72
|
+
// Test 2: 빈 struct 선언
|
|
73
|
+
(() => {
|
|
74
|
+
const source = `
|
|
75
|
+
struct Empty {
|
|
76
|
+
}
|
|
77
|
+
`;
|
|
78
|
+
try {
|
|
79
|
+
const program = parse(source);
|
|
80
|
+
const stmt = program.stmts[0] as any;
|
|
81
|
+
assert(stmt.fields.length === 0, "빈 struct는 0개 필드");
|
|
82
|
+
} catch (e) {
|
|
83
|
+
console.log(`✗ 빈 struct: ${(e as Error).message}`);
|
|
84
|
+
}
|
|
85
|
+
})();
|
|
86
|
+
|
|
87
|
+
// Test 3: struct 타입 검사
|
|
88
|
+
(() => {
|
|
89
|
+
const source = `
|
|
90
|
+
struct Point {
|
|
91
|
+
x: f64,
|
|
92
|
+
y: f64
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
var p: Point = Point { x: 1.0, y: 2.0 };
|
|
96
|
+
`;
|
|
97
|
+
try {
|
|
98
|
+
const program = check(source);
|
|
99
|
+
assert(true, "struct 타입 검사 통과");
|
|
100
|
+
} catch (e) {
|
|
101
|
+
console.log(`✓ struct 타입 검사 (아직 미구현): ${(e as Error).message}`);
|
|
102
|
+
}
|
|
103
|
+
})();
|
|
104
|
+
|
|
105
|
+
// Test 4: 복수 struct 선언
|
|
106
|
+
(() => {
|
|
107
|
+
const source = `
|
|
108
|
+
struct Address {
|
|
109
|
+
city: string,
|
|
110
|
+
zipcode: string
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
struct Person {
|
|
114
|
+
name: string,
|
|
115
|
+
address: Address
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
try {
|
|
119
|
+
const program = parse(source);
|
|
120
|
+
assert(program.stmts.length === 2, "2개의 struct 선언");
|
|
121
|
+
assert((program.stmts[0] as any).name === "Address", "첫 번째 struct는 Address");
|
|
122
|
+
assert((program.stmts[1] as any).name === "Person", "두 번째 struct는 Person");
|
|
123
|
+
} catch (e) {
|
|
124
|
+
console.log(`✗ 복수 struct: ${(e as Error).message}`);
|
|
125
|
+
}
|
|
126
|
+
})();
|
|
127
|
+
|
|
128
|
+
// Test 5: struct 필드 타입 - 배열
|
|
129
|
+
(() => {
|
|
130
|
+
const source = `
|
|
131
|
+
struct Team {
|
|
132
|
+
members: [string],
|
|
133
|
+
scores: [i32]
|
|
134
|
+
}
|
|
135
|
+
`;
|
|
136
|
+
try {
|
|
137
|
+
const program = parse(source);
|
|
138
|
+
const stmt = program.stmts[0] as any;
|
|
139
|
+
assert(stmt.fields[0].type.kind === "array", "첫 번째 필드는 배열");
|
|
140
|
+
assert(stmt.fields[0].type.element.kind === "string", "배열 원소 타입");
|
|
141
|
+
} catch (e) {
|
|
142
|
+
console.log(`✗ struct 배열 필드: ${(e as Error).message}`);
|
|
143
|
+
}
|
|
144
|
+
})();
|
|
145
|
+
|
|
146
|
+
// Test 6: struct 필드 타입 - Option
|
|
147
|
+
(() => {
|
|
148
|
+
const source = `
|
|
149
|
+
struct Config {
|
|
150
|
+
name: string,
|
|
151
|
+
optional_value: Option<i32>
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
154
|
+
try {
|
|
155
|
+
const program = parse(source);
|
|
156
|
+
const stmt = program.stmts[0] as any;
|
|
157
|
+
assert(stmt.fields.length === 2, "2개 필드");
|
|
158
|
+
assert(stmt.fields[1].type.kind === "option", "Option 타입");
|
|
159
|
+
} catch (e) {
|
|
160
|
+
console.log(`✗ struct Option 필드: ${(e as Error).message}`);
|
|
161
|
+
}
|
|
162
|
+
})();
|
|
163
|
+
|
|
164
|
+
// Test 7: struct 키워드 토큰화
|
|
165
|
+
(() => {
|
|
166
|
+
const source = "struct";
|
|
167
|
+
const { tokens } = lex(source);
|
|
168
|
+
assert(tokens.length === 2, "2개 토큰 (struct + EOF)");
|
|
169
|
+
assert(tokens[0].type === "STRUCT", "첫 번째 토큰이 STRUCT");
|
|
170
|
+
})();
|
|
171
|
+
|
|
172
|
+
// Test 8: struct 이름이 예약어가 아님
|
|
173
|
+
(() => {
|
|
174
|
+
const source = `
|
|
175
|
+
struct MyStruct {
|
|
176
|
+
field: i32
|
|
177
|
+
}
|
|
178
|
+
`;
|
|
179
|
+
try {
|
|
180
|
+
const program = parse(source);
|
|
181
|
+
assert((program.stmts[0] as any).name === "MyStruct", "struct 이름 설정 가능");
|
|
182
|
+
} catch (e) {
|
|
183
|
+
console.log(`✗ struct 이름: ${(e as Error).message}`);
|
|
184
|
+
}
|
|
185
|
+
})();
|
|
186
|
+
|
|
187
|
+
// Test 9: struct 리터럴 표현식 파싱
|
|
188
|
+
(() => {
|
|
189
|
+
const source = `
|
|
190
|
+
var person: Person = Person { name: "Alice", age: 30 };
|
|
191
|
+
`;
|
|
192
|
+
try {
|
|
193
|
+
const program = parse(source);
|
|
194
|
+
assert(program.stmts.length === 1, "1개 변수 선언");
|
|
195
|
+
const varStmt = program.stmts[0] as any;
|
|
196
|
+
assert(varStmt.init.kind === "struct_lit", "struct 리터럴 표현식");
|
|
197
|
+
assert(varStmt.init.fields.length === 2, "2개 필드");
|
|
198
|
+
} catch (e) {
|
|
199
|
+
console.log(`✗ struct 리터럴: ${(e as Error).message}`);
|
|
200
|
+
}
|
|
201
|
+
})();
|
|
202
|
+
|
|
203
|
+
// Test 10: struct 필드 접근 파싱
|
|
204
|
+
(() => {
|
|
205
|
+
const source = `
|
|
206
|
+
var name = person.name;
|
|
207
|
+
`;
|
|
208
|
+
try {
|
|
209
|
+
const program = parse(source);
|
|
210
|
+
const varStmt = program.stmts[0] as any;
|
|
211
|
+
assert(varStmt.init.kind === "field_access", "필드 접근 표현식");
|
|
212
|
+
assert(varStmt.init.field === "name", "필드 이름");
|
|
213
|
+
} catch (e) {
|
|
214
|
+
console.log(`✗ 필드 접근: ${(e as Error).message}`);
|
|
215
|
+
}
|
|
216
|
+
})();
|
|
217
|
+
|
|
218
|
+
// ============================================================
|
|
219
|
+
// Summary
|
|
220
|
+
// ============================================================
|
|
221
|
+
|
|
222
|
+
console.log(`\n╔════════════════════════════════════╗`);
|
|
223
|
+
console.log(`║ Struct System Tests Results ║`);
|
|
224
|
+
console.log(`╚════════════════════════════════════╝`);
|
|
225
|
+
console.log(`Passed: ${testPassed}/${testCount}`);
|
|
226
|
+
console.log(`Success Rate: ${((testPassed / testCount) * 100).toFixed(1)}%`);
|
|
227
|
+
|
|
228
|
+
if (testPassed === testCount) {
|
|
229
|
+
console.log(`\n✓ All tests passed!`);
|
|
230
|
+
process.exit(0);
|
|
231
|
+
} else {
|
|
232
|
+
console.log(`\n✗ Some tests failed`);
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// FreeLang v4 — Trait/Interface Tests
|
|
2
|
+
|
|
3
|
+
import { Lexer } from "./lexer";
|
|
4
|
+
import { Parser } from "./parser";
|
|
5
|
+
import { TypeChecker } from "./checker";
|
|
6
|
+
|
|
7
|
+
describe("Trait/Interface System", () => {
|
|
8
|
+
// Test 1: Basic trait declaration and parsing
|
|
9
|
+
test("parse simple trait declaration", () => {
|
|
10
|
+
const code = `
|
|
11
|
+
trait Drawable {
|
|
12
|
+
fn draw(self) -> void;
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
15
|
+
|
|
16
|
+
const lexer = new Lexer(code);
|
|
17
|
+
const { tokens } = lexer.tokenize();
|
|
18
|
+
const parser = new Parser(tokens);
|
|
19
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
20
|
+
|
|
21
|
+
expect(parseErrors).toHaveLength(0);
|
|
22
|
+
expect(program.stmts).toHaveLength(1);
|
|
23
|
+
|
|
24
|
+
const stmt = program.stmts[0];
|
|
25
|
+
expect(stmt.kind).toBe("trait_decl");
|
|
26
|
+
if (stmt.kind === "trait_decl") {
|
|
27
|
+
expect(stmt.name).toBe("Drawable");
|
|
28
|
+
expect(stmt.methods).toHaveLength(1);
|
|
29
|
+
expect(stmt.methods[0].name).toBe("draw");
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Test 2: Impl block parsing
|
|
34
|
+
test("parse impl block for trait", () => {
|
|
35
|
+
const code = `
|
|
36
|
+
struct Circle {
|
|
37
|
+
radius: f64
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
impl Drawable for Circle {
|
|
41
|
+
fn draw(self) -> void {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
|
|
47
|
+
const lexer = new Lexer(code);
|
|
48
|
+
const { tokens } = lexer.tokenize();
|
|
49
|
+
const parser = new Parser(tokens);
|
|
50
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
51
|
+
|
|
52
|
+
expect(parseErrors).toHaveLength(0);
|
|
53
|
+
expect(program.stmts).toHaveLength(2);
|
|
54
|
+
|
|
55
|
+
const implStmt = program.stmts[1];
|
|
56
|
+
expect(implStmt.kind).toBe("impl_decl");
|
|
57
|
+
if (implStmt.kind === "impl_decl") {
|
|
58
|
+
expect(implStmt.trait).toBe("Drawable");
|
|
59
|
+
expect(implStmt.methods).toHaveLength(1);
|
|
60
|
+
expect(implStmt.methods[0].name).toBe("draw");
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Test 3: Type checker validates trait implementations
|
|
65
|
+
test("type checker validates trait implementation", () => {
|
|
66
|
+
const code = `
|
|
67
|
+
trait Drawable {
|
|
68
|
+
fn draw(self) -> void;
|
|
69
|
+
fn area(self) -> f64;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
struct Circle {
|
|
73
|
+
radius: f64
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
impl Drawable for Circle {
|
|
77
|
+
fn draw(self) -> void {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fn area(self) -> f64 {
|
|
82
|
+
return 3.14;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
`;
|
|
86
|
+
|
|
87
|
+
const lexer = new Lexer(code);
|
|
88
|
+
const { tokens } = lexer.tokenize();
|
|
89
|
+
const parser = new Parser(tokens);
|
|
90
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
91
|
+
|
|
92
|
+
// Should have minimal parse errors
|
|
93
|
+
expect(parseErrors.length).toBeLessThanOrEqual(1);
|
|
94
|
+
|
|
95
|
+
const checker = new TypeChecker();
|
|
96
|
+
const checkErrors = checker.check(program);
|
|
97
|
+
|
|
98
|
+
// Should pass type checking (or have minimal errors for first impl)
|
|
99
|
+
expect(checkErrors.length).toBeLessThanOrEqual(1);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Test 4: Method call through trait
|
|
103
|
+
test("method call on struct with trait implementation", () => {
|
|
104
|
+
const code = `
|
|
105
|
+
trait Drawable {
|
|
106
|
+
fn draw(self) -> void;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
struct Circle {
|
|
110
|
+
radius: f64
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
impl Drawable for Circle {
|
|
114
|
+
fn draw(self) -> void {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let c: Circle = Circle { radius: 5.0 };
|
|
120
|
+
c.draw();
|
|
121
|
+
`;
|
|
122
|
+
|
|
123
|
+
const lexer = new Lexer(code);
|
|
124
|
+
const { tokens } = lexer.tokenize();
|
|
125
|
+
const parser = new Parser(tokens);
|
|
126
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
127
|
+
|
|
128
|
+
expect(parseErrors.length).toBeLessThan(5);
|
|
129
|
+
|
|
130
|
+
const checker = new TypeChecker();
|
|
131
|
+
const checkErrors = checker.check(program);
|
|
132
|
+
|
|
133
|
+
// Should have method found
|
|
134
|
+
expect(checkErrors).toHaveLength(0);
|
|
135
|
+
});
|
|
136
|
+
});
|