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
package/src/ast.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// FreeLang v4 — AST 노드 정의
|
|
2
|
+
|
|
3
|
+
// ============================================================
|
|
4
|
+
// 타입 표기 (Type Annotations)
|
|
5
|
+
// ============================================================
|
|
6
|
+
|
|
7
|
+
export type TypeAnnotation =
|
|
8
|
+
| { kind: "i32" }
|
|
9
|
+
| { kind: "i64" }
|
|
10
|
+
| { kind: "f64" }
|
|
11
|
+
| { kind: "bool" }
|
|
12
|
+
| { kind: "string" }
|
|
13
|
+
| { kind: "void" }
|
|
14
|
+
| { kind: "array"; element: TypeAnnotation }
|
|
15
|
+
| { kind: "channel"; element: TypeAnnotation }
|
|
16
|
+
| { kind: "option"; element: TypeAnnotation }
|
|
17
|
+
| { kind: "result"; ok: TypeAnnotation; err: TypeAnnotation }
|
|
18
|
+
| { kind: "promise"; element: TypeAnnotation }
|
|
19
|
+
| { kind: "struct_ref"; name: string }
|
|
20
|
+
| { kind: "fn"; params: TypeAnnotation[]; returnType: TypeAnnotation }
|
|
21
|
+
| { kind: "type_param"; name: string } // Generic 타입 파라미터 (T, K, V)
|
|
22
|
+
| { kind: "generic_ref"; name: string; typeArgs: TypeAnnotation[] } // 제네릭 타입 참조 (List<T>, Map<K,V>)
|
|
23
|
+
| { kind: "trait_ref"; name: string } // Trait 참조 (Drawable)
|
|
24
|
+
| { kind: "self_type" }; // Self 타입
|
|
25
|
+
|
|
26
|
+
// ============================================================
|
|
27
|
+
// 패턴 (Match Patterns) — SPEC_05 Q8: 7종
|
|
28
|
+
// ============================================================
|
|
29
|
+
|
|
30
|
+
export type Pattern =
|
|
31
|
+
| { kind: "ident"; name: string } // x → 바인딩
|
|
32
|
+
| { kind: "literal"; value: Expr } // 42, "hello", true
|
|
33
|
+
| { kind: "ok"; inner: Pattern } // Ok(v)
|
|
34
|
+
| { kind: "err"; inner: Pattern } // Err(e)
|
|
35
|
+
| { kind: "some"; inner: Pattern } // Some(v)
|
|
36
|
+
| { kind: "none" } // None
|
|
37
|
+
| { kind: "wildcard" } // _
|
|
38
|
+
| { kind: "struct"; name: string; fields: { name: string; pattern: Pattern; alias?: string }[]; rest: boolean } // Point { x, y }
|
|
39
|
+
| { kind: "array"; elements: Pattern[]; rest: boolean; restIndex?: number } // [a, b, c]
|
|
40
|
+
| { kind: "tuple"; elements: Pattern[]; rest: boolean; restIndex?: number }; // (a, b, c)
|
|
41
|
+
|
|
42
|
+
export type MatchArm = {
|
|
43
|
+
pattern: Pattern;
|
|
44
|
+
guard?: Expr; // if 조건절
|
|
45
|
+
body: Expr;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// ============================================================
|
|
49
|
+
// 식 (Expressions) — 값을 만든다
|
|
50
|
+
// ============================================================
|
|
51
|
+
|
|
52
|
+
export type FnParam = {
|
|
53
|
+
name: string;
|
|
54
|
+
type?: TypeAnnotation;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type Expr =
|
|
58
|
+
| { kind: "int_lit"; value: number; line: number; col: number }
|
|
59
|
+
| { kind: "float_lit"; value: number; line: number; col: number }
|
|
60
|
+
| { kind: "string_lit"; value: string; line: number; col: number }
|
|
61
|
+
| { kind: "bool_lit"; value: boolean; line: number; col: number }
|
|
62
|
+
| { kind: "ident"; name: string; line: number; col: number }
|
|
63
|
+
| { kind: "binary"; op: string; left: Expr; right: Expr; line: number; col: number }
|
|
64
|
+
| { kind: "unary"; op: string; operand: Expr; line: number; col: number }
|
|
65
|
+
| { kind: "await"; expr: Expr; line: number; col: number }
|
|
66
|
+
| { kind: "call"; callee: Expr; args: Expr[]; typeArgs?: TypeAnnotation[]; line: number; col: number }
|
|
67
|
+
| { kind: "index"; object: Expr; index: Expr; line: number; col: number }
|
|
68
|
+
| { kind: "field_access"; object: Expr; field: string; line: number; col: number }
|
|
69
|
+
| { kind: "assign"; target: Expr; value: Expr; line: number; col: number }
|
|
70
|
+
| { kind: "try"; operand: Expr; line: number; col: number }
|
|
71
|
+
| { kind: "if_expr"; condition: Expr; then: Expr[]; else_: Expr[]; line: number; col: number }
|
|
72
|
+
| { kind: "match_expr"; subject: Expr; arms: MatchArm[]; line: number; col: number }
|
|
73
|
+
| { kind: "array_lit"; elements: Expr[]; line: number; col: number }
|
|
74
|
+
| { kind: "struct_lit"; structName: string; fields: { name: string; value: Expr }[]; line: number; col: number }
|
|
75
|
+
| { kind: "fn_lit"; params: FnParam[]; returnType?: TypeAnnotation; body: Expr; line: number; col: number }
|
|
76
|
+
| { kind: "block_expr"; stmts: Stmt[]; expr: Expr | null; line: number; col: number }
|
|
77
|
+
| { kind: "chan_new"; element: TypeAnnotation; line: number; col: number }
|
|
78
|
+
| { kind: "chan_send"; chan: Expr; value: Expr; line: number; col: number }
|
|
79
|
+
| { kind: "chan_recv"; chan: Expr; line: number; col: number };
|
|
80
|
+
|
|
81
|
+
// ============================================================
|
|
82
|
+
// 문 (Statements) — 값을 만들지 않는다
|
|
83
|
+
// ============================================================
|
|
84
|
+
|
|
85
|
+
export type Param = {
|
|
86
|
+
name: string;
|
|
87
|
+
type: TypeAnnotation;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export type StructField = {
|
|
91
|
+
name: string;
|
|
92
|
+
type: TypeAnnotation;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export type TraitMethod = {
|
|
96
|
+
name: string;
|
|
97
|
+
params: Param[];
|
|
98
|
+
returnType: TypeAnnotation;
|
|
99
|
+
line: number;
|
|
100
|
+
col: number;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export type ImplMethod = {
|
|
104
|
+
name: string;
|
|
105
|
+
params: Param[];
|
|
106
|
+
returnType: TypeAnnotation;
|
|
107
|
+
body: Stmt[];
|
|
108
|
+
line: number;
|
|
109
|
+
col: number;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export type ImportItem = {
|
|
113
|
+
name: string;
|
|
114
|
+
alias?: string;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export type ImportDecl = {
|
|
118
|
+
kind: "import_decl";
|
|
119
|
+
source: string;
|
|
120
|
+
items: ImportItem[];
|
|
121
|
+
default?: boolean;
|
|
122
|
+
line: number;
|
|
123
|
+
col: number;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export type ExportDecl = {
|
|
127
|
+
kind: "export_decl";
|
|
128
|
+
target: Stmt | string[];
|
|
129
|
+
line: number;
|
|
130
|
+
col: number;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export type Stmt =
|
|
134
|
+
| { kind: "var_decl"; name: string; mutable: boolean; type: TypeAnnotation | null; init: Expr; line: number; col: number }
|
|
135
|
+
| { kind: "fn_decl"; name: string; isAsync: boolean; typeParams: string[]; params: Param[]; returnType: TypeAnnotation; body: Stmt[]; line: number; col: number }
|
|
136
|
+
| { kind: "struct_decl"; name: string; typeParams: string[]; fields: StructField[]; line: number; col: number }
|
|
137
|
+
| { kind: "trait_decl"; name: string; typeParams: string[]; methods: TraitMethod[]; line: number; col: number }
|
|
138
|
+
| { kind: "impl_decl"; trait: string | null; forType: TypeAnnotation; typeParams: string[]; methods: ImplMethod[]; line: number; col: number }
|
|
139
|
+
| { kind: "if_stmt"; condition: Expr; then: Stmt[]; else_: Stmt[] | null; line: number; col: number }
|
|
140
|
+
| { kind: "match_stmt"; subject: Expr; arms: MatchArm[]; line: number; col: number }
|
|
141
|
+
| { kind: "for_stmt"; variable: string; iterable: Expr; body: Stmt[]; line: number; col: number }
|
|
142
|
+
| { kind: "for_of_stmt"; variable: string; iterable: Expr; body: Stmt[]; line: number; col: number }
|
|
143
|
+
| { kind: "while_stmt"; condition: Expr; body: Stmt[]; line: number; col: number }
|
|
144
|
+
| { kind: "break_stmt"; line: number; col: number }
|
|
145
|
+
| { kind: "continue_stmt"; line: number; col: number }
|
|
146
|
+
| { kind: "spawn_stmt"; body: Stmt[]; line: number; col: number }
|
|
147
|
+
| { kind: "return_stmt"; value: Expr | null; line: number; col: number }
|
|
148
|
+
| { kind: "expr_stmt"; expr: Expr; line: number; col: number }
|
|
149
|
+
| ImportDecl
|
|
150
|
+
| ExportDecl;
|
|
151
|
+
|
|
152
|
+
// ============================================================
|
|
153
|
+
// 프로그램 (최상위)
|
|
154
|
+
// ============================================================
|
|
155
|
+
|
|
156
|
+
export type Program = {
|
|
157
|
+
stmts: Stmt[];
|
|
158
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// FreeLang v4 — Async/Await 기본 기능 테스트
|
|
2
|
+
// 최소 3/5 테스트 통과를 목표로 함
|
|
3
|
+
|
|
4
|
+
import { Lexer } from "./lexer";
|
|
5
|
+
import { Parser } from "./parser";
|
|
6
|
+
import { TypeChecker } from "./checker";
|
|
7
|
+
import { Compiler } from "./compiler";
|
|
8
|
+
|
|
9
|
+
describe("Async/Await Basic Implementation", () => {
|
|
10
|
+
function testParse(source: string) {
|
|
11
|
+
const lexer = new Lexer(source);
|
|
12
|
+
const { tokens, errors: lexErrors } = lexer.tokenize();
|
|
13
|
+
if (lexErrors.length > 0) {
|
|
14
|
+
throw new Error(`Lex: ${lexErrors[0].message}`);
|
|
15
|
+
}
|
|
16
|
+
const parser = new Parser(tokens);
|
|
17
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
18
|
+
if (parseErrors.length > 0) {
|
|
19
|
+
throw new Error(`Parse: ${parseErrors[0].message}`);
|
|
20
|
+
}
|
|
21
|
+
return program;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function testTypeCheck(program: any) {
|
|
25
|
+
const checker = new TypeChecker();
|
|
26
|
+
const errors = checker.check(program);
|
|
27
|
+
return errors;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function testCompile(program: any) {
|
|
31
|
+
const compiler = new Compiler();
|
|
32
|
+
const chunk = compiler.compile(program);
|
|
33
|
+
return chunk;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Test 1: async fn 선언 파싱
|
|
37
|
+
it("T1: Parse async fn declaration", () => {
|
|
38
|
+
const source = `async fn getValue(): Promise<i32> { return 42 }`;
|
|
39
|
+
const program = testParse(source);
|
|
40
|
+
expect(program.stmts.length).toBe(1);
|
|
41
|
+
const fnStmt = program.stmts[0];
|
|
42
|
+
expect(fnStmt.kind).toBe("fn_decl");
|
|
43
|
+
expect((fnStmt as any).isAsync).toBe(true);
|
|
44
|
+
expect((fnStmt as any).name).toBe("getValue");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Test 2: Promise<T> 타입 파싱
|
|
48
|
+
it("T2: Parse Promise<T> type annotation", () => {
|
|
49
|
+
const source = `async fn getStr(): Promise<string> { return "ok" }`;
|
|
50
|
+
const program = testParse(source);
|
|
51
|
+
const fnStmt = program.stmts[0] as any;
|
|
52
|
+
expect(fnStmt.returnType.kind).toBe("promise");
|
|
53
|
+
expect(fnStmt.returnType.element.kind).toBe("string");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Test 3: await 식 파싱
|
|
57
|
+
it("T3: Parse await expression", () => {
|
|
58
|
+
const source = `async fn caller(): Promise<i32> { let x = await getValue(); return x }`;
|
|
59
|
+
const program = testParse(source);
|
|
60
|
+
const fnStmt = program.stmts[0] as any;
|
|
61
|
+
const bodyHasAwait = fnStmt.body.some((stmt: any) => {
|
|
62
|
+
if (stmt.kind === "var_decl") {
|
|
63
|
+
return stmt.init.kind === "await";
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
});
|
|
67
|
+
expect(bodyHasAwait).toBe(true);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Test 4: async fn 타입 검사 (Promise 자동 변환)
|
|
71
|
+
it("T4: Type check async fn returns Promise<T>", () => {
|
|
72
|
+
const source = `async fn getValue(): i32 { return 42 }`;
|
|
73
|
+
const program = testParse(source);
|
|
74
|
+
// 타입 체커는 async fn의 반환 타입을 Promise<T>로 자동 변환
|
|
75
|
+
const errors = testTypeCheck(program);
|
|
76
|
+
expect(errors.length).toBe(0);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Test 5: await에 Promise 요구
|
|
80
|
+
it("T5: Type check await requires Promise", () => {
|
|
81
|
+
const source = `
|
|
82
|
+
async fn caller(): Promise<i32> {
|
|
83
|
+
let x = await getValue()
|
|
84
|
+
return x
|
|
85
|
+
}
|
|
86
|
+
fn getValue(): i32 { return 42 }
|
|
87
|
+
`;
|
|
88
|
+
const program = testParse(source);
|
|
89
|
+
const errors = testTypeCheck(program);
|
|
90
|
+
// await getValue()에서 getValue()는 i32를 반환하므로 에러
|
|
91
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
92
|
+
expect(errors[0].message).toContain("await");
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// FreeLang v4 — Async/Await 기본 테스트
|
|
2
|
+
// Promise 기반 구현
|
|
3
|
+
|
|
4
|
+
import { Lexer } from "./lexer";
|
|
5
|
+
import { Parser } from "./parser";
|
|
6
|
+
import { TypeChecker } from "./checker";
|
|
7
|
+
import { Compiler } from "./compiler";
|
|
8
|
+
|
|
9
|
+
describe("Async/Await Basic Support", () => {
|
|
10
|
+
function compile(source: string) {
|
|
11
|
+
const lexer = new Lexer(source);
|
|
12
|
+
const { tokens, errors: lexErrors } = lexer.tokenize();
|
|
13
|
+
if (lexErrors.length > 0) {
|
|
14
|
+
throw new Error(`Lex errors: ${lexErrors.map(e => e.message).join(", ")}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const parser = new Parser(tokens);
|
|
18
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
19
|
+
if (parseErrors.length > 0) {
|
|
20
|
+
throw new Error(`Parse errors: ${parseErrors.map(e => e.message).join(", ")}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const checker = new TypeChecker();
|
|
24
|
+
const checkErrors = checker.check(program);
|
|
25
|
+
if (checkErrors.length > 0) {
|
|
26
|
+
throw new Error(`Type errors: ${checkErrors.map(e => e.message).join(", ")}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const compiler = new Compiler();
|
|
30
|
+
const chunk = compiler.compile(program);
|
|
31
|
+
return chunk;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// T1: 기본 async 함수 선언
|
|
35
|
+
test("T1: Basic async function declaration", () => {
|
|
36
|
+
const source = `
|
|
37
|
+
async fn simple(): Promise<i32> {
|
|
38
|
+
return 42
|
|
39
|
+
}
|
|
40
|
+
`;
|
|
41
|
+
expect(() => compile(source)).not.toThrow();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// T2: async 함수에서 값 반환
|
|
45
|
+
test("T2: Async function with return value", () => {
|
|
46
|
+
const source = `
|
|
47
|
+
async fn getValue(): Promise<string> {
|
|
48
|
+
return "hello"
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
51
|
+
expect(() => compile(source)).not.toThrow();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// T3: await 식 파싱
|
|
55
|
+
test("T3: Await expression parsing", () => {
|
|
56
|
+
const source = `
|
|
57
|
+
async fn delayed(): Promise<i32> {
|
|
58
|
+
let x = await getValue()
|
|
59
|
+
return x
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
fn getValue(): i32 {
|
|
63
|
+
return 42
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
66
|
+
// 이 테스트는 타입 체크 에러가 발생할 것으로 예상
|
|
67
|
+
// getValue는 Promise를 반환하지 않으므로
|
|
68
|
+
const lexer = new Lexer(source);
|
|
69
|
+
const { tokens } = lexer.tokenize();
|
|
70
|
+
const parser = new Parser(tokens);
|
|
71
|
+
const { program } = parser.parse();
|
|
72
|
+
|
|
73
|
+
const checker = new TypeChecker();
|
|
74
|
+
const errors = checker.check(program);
|
|
75
|
+
// await는 Promise 타입을 요구하므로 에러가 나야 함
|
|
76
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// T4: Promise 타입 호환성
|
|
80
|
+
test("T4: Promise type compatibility", () => {
|
|
81
|
+
const source = `
|
|
82
|
+
async fn asyncFunc(): Promise<i32> {
|
|
83
|
+
return 42
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fn caller(): Promise<i32> {
|
|
87
|
+
return asyncFunc()
|
|
88
|
+
}
|
|
89
|
+
`;
|
|
90
|
+
expect(() => compile(source)).not.toThrow();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// T5: await로 Promise 언래핑
|
|
94
|
+
test("T5: Await unwraps Promise type", () => {
|
|
95
|
+
const source = `
|
|
96
|
+
async fn getValue(): Promise<i32> {
|
|
97
|
+
return 42
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async fn caller(): Promise<i32> {
|
|
101
|
+
let result = await getValue()
|
|
102
|
+
return result
|
|
103
|
+
}
|
|
104
|
+
`;
|
|
105
|
+
expect(() => compile(source)).not.toThrow();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// FreeLang v4 — 채널/Actor 통합 테스트
|
|
2
|
+
|
|
3
|
+
import { Lexer } from "./lexer";
|
|
4
|
+
import { Parser } from "./parser";
|
|
5
|
+
import { TypeChecker } from "./checker";
|
|
6
|
+
import { Compiler } from "./compiler";
|
|
7
|
+
import { VM } from "./vm";
|
|
8
|
+
|
|
9
|
+
async function runCode(code: string): Promise<string[]> {
|
|
10
|
+
const lexer = new Lexer(code);
|
|
11
|
+
const { tokens, errors: lexErrors } = lexer.tokenize();
|
|
12
|
+
if (lexErrors.length > 0) {
|
|
13
|
+
throw new Error(`Lex errors: ${lexErrors.map((e) => e.message).join(", ")}`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const parser = new Parser(tokens);
|
|
17
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
18
|
+
if (parseErrors.length > 0) {
|
|
19
|
+
throw new Error(`Parse errors: ${parseErrors.map((e) => e.message).join(", ")}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const checker = new TypeChecker();
|
|
23
|
+
const checkErrors = checker.check(program);
|
|
24
|
+
if (checkErrors.length > 0) {
|
|
25
|
+
throw new Error(`Type errors: ${checkErrors.map((e: any) => e.message).join(", ")}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const compiler = new Compiler();
|
|
29
|
+
const bytecode = compiler.compile(program);
|
|
30
|
+
|
|
31
|
+
const vm = new VM();
|
|
32
|
+
const { output, error } = await vm.run(bytecode);
|
|
33
|
+
if (error) {
|
|
34
|
+
throw new Error(`Runtime error: ${error}`);
|
|
35
|
+
}
|
|
36
|
+
return output;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("Channel/Actor 기본 테스트", () => {
|
|
40
|
+
// 테스트 1: 채널 생성
|
|
41
|
+
test("T1: 채널 생성 (chan_new)", async () => {
|
|
42
|
+
const code = `
|
|
43
|
+
var ch = channel<i32>();
|
|
44
|
+
println(str(1));
|
|
45
|
+
`;
|
|
46
|
+
const output = await runCode(code);
|
|
47
|
+
expect(output).toContain("1");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// 테스트 2: 채널 송수신 (기본)
|
|
51
|
+
test("T2: 채널 송수신 (spawn에서 송신, 메인에서 수신)", async () => {
|
|
52
|
+
const code = `
|
|
53
|
+
var ch = channel<i32>();
|
|
54
|
+
|
|
55
|
+
spawn {
|
|
56
|
+
ch <- 42;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var x = <- ch;
|
|
60
|
+
println(str(x));
|
|
61
|
+
`;
|
|
62
|
+
const output = await runCode(code);
|
|
63
|
+
expect(output).toContain("42");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// 테스트 3: 다중 메시지
|
|
67
|
+
test("T3: 채널을 통한 다중 메시지 송수신", async () => {
|
|
68
|
+
const code = `
|
|
69
|
+
var ch = channel<i32>();
|
|
70
|
+
|
|
71
|
+
spawn {
|
|
72
|
+
ch <- 10;
|
|
73
|
+
ch <- 20;
|
|
74
|
+
ch <- 30;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
var a = <- ch;
|
|
78
|
+
var b = <- ch;
|
|
79
|
+
var c = <- ch;
|
|
80
|
+
println(str(a));
|
|
81
|
+
println(str(b));
|
|
82
|
+
println(str(c));
|
|
83
|
+
`;
|
|
84
|
+
const output = await runCode(code);
|
|
85
|
+
expect(output).toContain("10");
|
|
86
|
+
expect(output).toContain("20");
|
|
87
|
+
expect(output).toContain("30");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// 테스트 4: 다중 Actor (2개)
|
|
91
|
+
test("T4: 다중 Actor 간 통신 (2 spawns)", async () => {
|
|
92
|
+
const code = `
|
|
93
|
+
var ch1 = channel<i32>();
|
|
94
|
+
|
|
95
|
+
spawn {
|
|
96
|
+
ch1 <- 100;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
var y = <- ch1;
|
|
100
|
+
println(str(y));
|
|
101
|
+
`;
|
|
102
|
+
const output = await runCode(code);
|
|
103
|
+
expect(output).toContain("100");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// 테스트 5: 채널 타입 체크 (mismatch 감지)
|
|
107
|
+
test("T5: 채널 타입 미스매치 감지", async () => {
|
|
108
|
+
const code = `
|
|
109
|
+
var ch = channel<i32>();
|
|
110
|
+
ch <- "hello";
|
|
111
|
+
`;
|
|
112
|
+
await expect(runCode(code)).rejects.toThrow();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// 테스트 6: Actor 스케줄링 (순서 검증)
|
|
116
|
+
test("T6: Actor 스케줄링 순서 검증", async () => {
|
|
117
|
+
const code = `
|
|
118
|
+
var ch = channel<i32>();
|
|
119
|
+
|
|
120
|
+
spawn {
|
|
121
|
+
ch <- 1;
|
|
122
|
+
ch <- 2;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
var x = <- ch;
|
|
126
|
+
var y = <- ch;
|
|
127
|
+
println(str(x));
|
|
128
|
+
println(str(y));
|
|
129
|
+
`;
|
|
130
|
+
const output = await runCode(code);
|
|
131
|
+
expect(output[0]).toBe("1");
|
|
132
|
+
expect(output[1]).toBe("2");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// 테스트 7: 복잡한 채널 패턴
|
|
136
|
+
test("T7: 복잡한 채널 패턴 (2개 채널)", async () => {
|
|
137
|
+
const code = `
|
|
138
|
+
var ch_a = channel<i32>();
|
|
139
|
+
var ch_b = channel<i32>();
|
|
140
|
+
|
|
141
|
+
spawn {
|
|
142
|
+
ch_a <- 1;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
spawn {
|
|
146
|
+
ch_b <- 2;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
var a = <- ch_a;
|
|
150
|
+
var b = <- ch_b;
|
|
151
|
+
println(str(a));
|
|
152
|
+
println(str(b));
|
|
153
|
+
`;
|
|
154
|
+
const output = await runCode(code);
|
|
155
|
+
expect(output).toContain("1");
|
|
156
|
+
expect(output).toContain("2");
|
|
157
|
+
});
|
|
158
|
+
});
|