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/main.ts
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// FreeLang v4 — CLI Entry Point
|
|
3
|
+
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import { Lexer } from "./lexer";
|
|
6
|
+
import { Parser } from "./parser";
|
|
7
|
+
import { TypeChecker } from "./checker";
|
|
8
|
+
import { Compiler } from "./compiler";
|
|
9
|
+
import { VM } from "./vm";
|
|
10
|
+
import { IRGen } from "./ir-gen";
|
|
11
|
+
import { REPL } from "./repl";
|
|
12
|
+
import { SQLiteDB, MigrationManager } from "./db";
|
|
13
|
+
|
|
14
|
+
async function main(): Promise<void> {
|
|
15
|
+
const args = process.argv.slice(2);
|
|
16
|
+
|
|
17
|
+
// 버전 확인
|
|
18
|
+
if (args[0] === "--version" || args[0] === "-v") {
|
|
19
|
+
console.log("FreeLang 4.1.0");
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// REPL 모드
|
|
24
|
+
if (args[0] === "--repl" || args[0] === "-i") {
|
|
25
|
+
const repl = new REPL();
|
|
26
|
+
await repl.start();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 마이그레이션 CLI
|
|
31
|
+
if (args[0] === "migrate") {
|
|
32
|
+
const cmd = args[1];
|
|
33
|
+
const dbPath = args[2] || "./app.db";
|
|
34
|
+
const migrationsDir = args[3] || "./migrations";
|
|
35
|
+
|
|
36
|
+
const db = new SQLiteDB(dbPath);
|
|
37
|
+
const manager = new MigrationManager(db, migrationsDir);
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
if (cmd === "up") {
|
|
41
|
+
await db.init();
|
|
42
|
+
await manager.up();
|
|
43
|
+
await db.close();
|
|
44
|
+
} else if (cmd === "down") {
|
|
45
|
+
await db.init();
|
|
46
|
+
await manager.down();
|
|
47
|
+
await db.close();
|
|
48
|
+
} else if (cmd === "status") {
|
|
49
|
+
await db.init();
|
|
50
|
+
const rows = await manager.status();
|
|
51
|
+
if (rows.length === 0) {
|
|
52
|
+
console.log("적용된 마이그레이션이 없습니다.");
|
|
53
|
+
} else {
|
|
54
|
+
console.log("적용된 마이그레이션:");
|
|
55
|
+
for (const row of rows) {
|
|
56
|
+
console.log(` - ${row.name} (${row.applied_at})`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
await db.close();
|
|
60
|
+
} else {
|
|
61
|
+
console.error(`unknown migrate command: ${cmd}`);
|
|
62
|
+
console.log("Usage:");
|
|
63
|
+
console.log(" freelang migrate up [db_path] [migrations_dir]");
|
|
64
|
+
console.log(" freelang migrate down [db_path] [migrations_dir]");
|
|
65
|
+
console.log(" freelang migrate status [db_path] [migrations_dir]");
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
} catch (e: any) {
|
|
69
|
+
console.error(`migrate error: ${e.message}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 패키지 매니저 CLI
|
|
76
|
+
if (args[0] === "init") {
|
|
77
|
+
const { initProject } = await import("./pkg/init");
|
|
78
|
+
await initProject(args[1] || "my-app");
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (args[0] === "install") {
|
|
83
|
+
const { installPackage } = await import("./pkg/install");
|
|
84
|
+
await installPackage(args[1], process.cwd());
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (args[0] === "run") {
|
|
89
|
+
const { runScript } = await import("./pkg/run");
|
|
90
|
+
await runScript(args[1], process.cwd());
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (args[0] === "list-packages") {
|
|
95
|
+
const { listPackages } = await import("./pkg/registry");
|
|
96
|
+
listPackages();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (args[0] === "search-packages") {
|
|
101
|
+
const { searchPackages } = await import("./pkg/registry");
|
|
102
|
+
searchPackages(args[1] || "");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// 웹 REPL
|
|
107
|
+
if (args[0] === "--web-repl") {
|
|
108
|
+
const portIdx = args.indexOf("--port");
|
|
109
|
+
const port = portIdx >= 0 ? parseInt(args[portIdx + 1]) : 3000;
|
|
110
|
+
const { startWebRepl } = await import("./web-repl/server");
|
|
111
|
+
await startWebRepl(port);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 도움말
|
|
116
|
+
if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
|
|
117
|
+
console.log("🦁 FreeLang v4.3 — AI-First Programming Language");
|
|
118
|
+
console.log("");
|
|
119
|
+
console.log("Usage:");
|
|
120
|
+
console.log(" freelang <file.fl> [options] 파일 실행");
|
|
121
|
+
console.log(" freelang --repl 대화형 쉘 시작");
|
|
122
|
+
console.log(" freelang --web-repl [--port PORT] 웹 REPL 시작");
|
|
123
|
+
console.log("");
|
|
124
|
+
console.log("Project Management:");
|
|
125
|
+
console.log(" freelang init [name] 새 프로젝트 생성");
|
|
126
|
+
console.log(" freelang install <pkg> 패키지 설치");
|
|
127
|
+
console.log(" freelang run <script> freelang.toml 스크립트 실행");
|
|
128
|
+
console.log(" freelang list-packages 전체 패키지 목록");
|
|
129
|
+
console.log(" freelang search-packages <query> 패키지 검색");
|
|
130
|
+
console.log("");
|
|
131
|
+
console.log("Database:");
|
|
132
|
+
console.log(" freelang migrate <cmd> [args] 마이그레이션 관리");
|
|
133
|
+
console.log("");
|
|
134
|
+
console.log("Options:");
|
|
135
|
+
console.log(" --no-check 타입 체크 건너뛰기");
|
|
136
|
+
console.log(" --dump-bc 바이트코드 덤프");
|
|
137
|
+
console.log(" --dump-ir IR(중간 표현) 덤프");
|
|
138
|
+
console.log(" --use-ir IR 경로로 컴파일");
|
|
139
|
+
console.log(" --help, -h 도움말 표시");
|
|
140
|
+
console.log(" --version 버전 표시");
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const file = args[0];
|
|
145
|
+
const noCheck = args.includes("--no-check");
|
|
146
|
+
const dumpBc = args.includes("--dump-bc");
|
|
147
|
+
const dumpIr = args.includes("--dump-ir");
|
|
148
|
+
const useIr = args.includes("--use-ir") || dumpIr;
|
|
149
|
+
|
|
150
|
+
// 파일 읽기
|
|
151
|
+
let source: string;
|
|
152
|
+
try {
|
|
153
|
+
source = fs.readFileSync(file, "utf-8");
|
|
154
|
+
} catch {
|
|
155
|
+
console.error(`error: cannot read file '${file}'`);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 1. Lexer
|
|
160
|
+
const { tokens, errors: lexErrors } = new Lexer(source).tokenize();
|
|
161
|
+
if (lexErrors.length > 0) {
|
|
162
|
+
for (const e of lexErrors) {
|
|
163
|
+
console.error(`${file}:${e.line}: lex error: ${e.message}`);
|
|
164
|
+
}
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// 2. Parser
|
|
169
|
+
const { program, errors: parseErrors } = new Parser(tokens).parse();
|
|
170
|
+
if (parseErrors.length > 0) {
|
|
171
|
+
for (const e of parseErrors) {
|
|
172
|
+
console.error(`${file}:${e.line}: parse error: ${e.message}`);
|
|
173
|
+
}
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// 3. TypeChecker (optional)
|
|
178
|
+
if (!noCheck) {
|
|
179
|
+
const checkErrors = new TypeChecker().check(program);
|
|
180
|
+
if (checkErrors.length > 0) {
|
|
181
|
+
for (const e of checkErrors) {
|
|
182
|
+
console.error(`${file}:${e.line}: type error: ${e.message}`);
|
|
183
|
+
}
|
|
184
|
+
process.exit(1);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 4. Compiler (IR 경로 vs 기존 경로)
|
|
189
|
+
let chunk;
|
|
190
|
+
if (useIr) {
|
|
191
|
+
const irProg = new IRGen().generate(program); // AST → IR
|
|
192
|
+
if (dumpIr) {
|
|
193
|
+
console.log(JSON.stringify(irProg, null, 2));
|
|
194
|
+
process.exit(0);
|
|
195
|
+
}
|
|
196
|
+
chunk = new Compiler().compileIR(irProg); // IR → Chunk
|
|
197
|
+
} else {
|
|
198
|
+
chunk = new Compiler().compile(program); // 기존 경로 유지
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (dumpBc) {
|
|
202
|
+
console.log(`--- bytecode (${chunk.code.length} bytes, ${chunk.functions.length} functions) ---`);
|
|
203
|
+
console.log(`constants: ${JSON.stringify(chunk.constants)}`);
|
|
204
|
+
for (const fn of chunk.functions) {
|
|
205
|
+
console.log(`fn ${fn.name}(arity=${fn.arity}) @ offset ${fn.offset}`);
|
|
206
|
+
}
|
|
207
|
+
process.exit(0);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 5. VM 실행
|
|
211
|
+
const { output, error } = await new VM().run(chunk);
|
|
212
|
+
|
|
213
|
+
for (const line of output) {
|
|
214
|
+
console.log(line);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (error) {
|
|
218
|
+
console.error(error);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
main().catch(console.error);
|
package/src/models.fl
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// FreeLang v4.2 — gogs-cli API 응답 모델
|
|
2
|
+
// Gogs API에서 반환하는 데이터 구조
|
|
3
|
+
|
|
4
|
+
// ==================== Repo Model ====================
|
|
5
|
+
|
|
6
|
+
struct Repo {
|
|
7
|
+
id: i32
|
|
8
|
+
owner: Owner
|
|
9
|
+
name: str
|
|
10
|
+
full_name: str
|
|
11
|
+
description: str
|
|
12
|
+
private: bool
|
|
13
|
+
fork: bool
|
|
14
|
+
html_url: str
|
|
15
|
+
ssh_url: str
|
|
16
|
+
clone_url: str
|
|
17
|
+
default_branch: str
|
|
18
|
+
created_at: str
|
|
19
|
+
updated_at: str
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
struct Owner {
|
|
23
|
+
id: i32
|
|
24
|
+
login: str
|
|
25
|
+
avatar_url: str
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
struct CreateRepoRequest {
|
|
29
|
+
name: str
|
|
30
|
+
description: str
|
|
31
|
+
private: bool
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ==================== User Model ====================
|
|
35
|
+
|
|
36
|
+
struct User {
|
|
37
|
+
id: i32
|
|
38
|
+
login: str
|
|
39
|
+
full_name: str
|
|
40
|
+
email: str
|
|
41
|
+
is_admin: bool
|
|
42
|
+
avatar_url: str
|
|
43
|
+
created_at: str
|
|
44
|
+
updated_at: str
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
struct CreateUserRequest {
|
|
48
|
+
username: str
|
|
49
|
+
email: str
|
|
50
|
+
password: str
|
|
51
|
+
send_notify: bool
|
|
52
|
+
is_admin: bool
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// ==================== Organization Model ====================
|
|
56
|
+
|
|
57
|
+
struct Organization {
|
|
58
|
+
id: i32
|
|
59
|
+
username: str
|
|
60
|
+
full_name: str
|
|
61
|
+
email: str
|
|
62
|
+
website: str
|
|
63
|
+
location: str
|
|
64
|
+
bio: str
|
|
65
|
+
avatar_url: str
|
|
66
|
+
created_at: str
|
|
67
|
+
updated_at: str
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
struct CreateOrgRequest {
|
|
71
|
+
username: str
|
|
72
|
+
full_name: str
|
|
73
|
+
email: str
|
|
74
|
+
website: str
|
|
75
|
+
location: str
|
|
76
|
+
bio: str
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ==================== Team Model ====================
|
|
80
|
+
|
|
81
|
+
struct Team {
|
|
82
|
+
id: i32
|
|
83
|
+
name: str
|
|
84
|
+
description: str
|
|
85
|
+
permission: str
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
struct CreateTeamRequest {
|
|
89
|
+
name: str
|
|
90
|
+
description: str
|
|
91
|
+
permission: str
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ==================== Issue Model ====================
|
|
95
|
+
|
|
96
|
+
struct Issue {
|
|
97
|
+
id: i32
|
|
98
|
+
number: i32
|
|
99
|
+
title: str
|
|
100
|
+
description: str
|
|
101
|
+
state: str // "open", "closed"
|
|
102
|
+
user: User
|
|
103
|
+
created_at: str
|
|
104
|
+
updated_at: str
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
struct CreateIssueRequest {
|
|
108
|
+
title: str
|
|
109
|
+
body: str
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// ==================== Webhook Model ====================
|
|
113
|
+
|
|
114
|
+
struct Webhook {
|
|
115
|
+
id: i32
|
|
116
|
+
url: str
|
|
117
|
+
content_type: str
|
|
118
|
+
events: [str]
|
|
119
|
+
active: bool
|
|
120
|
+
created_at: str
|
|
121
|
+
updated_at: str
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
struct CreateWebhookRequest {
|
|
125
|
+
url: str
|
|
126
|
+
content_type: str
|
|
127
|
+
events: [str]
|
|
128
|
+
active: bool
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ==================== Deploy Key Model ====================
|
|
132
|
+
|
|
133
|
+
struct DeployKey {
|
|
134
|
+
id: i32
|
|
135
|
+
key_id: i32
|
|
136
|
+
title: str
|
|
137
|
+
key: str
|
|
138
|
+
url: str
|
|
139
|
+
read_only: bool
|
|
140
|
+
created_at: str
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
struct CreateDeployKeyRequest {
|
|
144
|
+
title: str
|
|
145
|
+
key: str
|
|
146
|
+
read_only: bool
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ==================== Analysis Model ====================
|
|
150
|
+
|
|
151
|
+
struct RepositoryStats {
|
|
152
|
+
total: i32
|
|
153
|
+
public: i32
|
|
154
|
+
private: i32
|
|
155
|
+
recently_updated_7days: i32
|
|
156
|
+
by_updated: [Repo]
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
struct AnalysisResult {
|
|
160
|
+
timestamp: str
|
|
161
|
+
repository_stats: RepositoryStats
|
|
162
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// FreeLang v4 Module System Tests
|
|
2
|
+
// 기본 import/export 파싱 및 검증 테스트
|
|
3
|
+
|
|
4
|
+
import { Lexer } from "./lexer";
|
|
5
|
+
import { Parser } from "./parser";
|
|
6
|
+
import { TypeChecker } from "./checker";
|
|
7
|
+
import { Program, Stmt, ImportDecl, ExportDecl } from "./ast";
|
|
8
|
+
|
|
9
|
+
describe("Module System", () => {
|
|
10
|
+
// 헬퍼: 코드를 AST로 파싱
|
|
11
|
+
function parseCode(code: string): Program {
|
|
12
|
+
const lexer = new Lexer(code);
|
|
13
|
+
const { tokens, errors: lexErrors } = lexer.tokenize();
|
|
14
|
+
if (lexErrors.length > 0) {
|
|
15
|
+
throw new Error(`Lex errors: ${lexErrors.map(e => e.message).join(", ")}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const parser = new Parser(tokens);
|
|
19
|
+
const { program, errors: parseErrors } = parser.parse();
|
|
20
|
+
if (parseErrors.length > 0) {
|
|
21
|
+
throw new Error(`Parse errors: ${parseErrors.map(e => e.message).join(", ")}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return program;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Test 1: 기본 import 파싱
|
|
28
|
+
it("should parse basic import statement", () => {
|
|
29
|
+
const code = `import { add } from "./math";`;
|
|
30
|
+
const program = parseCode(code);
|
|
31
|
+
|
|
32
|
+
expect(program.stmts.length).toBe(1);
|
|
33
|
+
const stmt = program.stmts[0] as ImportDecl;
|
|
34
|
+
expect(stmt.kind).toBe("import_decl");
|
|
35
|
+
expect(stmt.source).toBe("./math");
|
|
36
|
+
expect(stmt.items.length).toBe(1);
|
|
37
|
+
expect(stmt.items[0].name).toBe("add");
|
|
38
|
+
expect(stmt.items[0].alias).toBeUndefined();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Test 2: 다중 항목 import
|
|
42
|
+
it("should parse multiple import items", () => {
|
|
43
|
+
const code = `import { add, subtract, multiply } from "./math";`;
|
|
44
|
+
const program = parseCode(code);
|
|
45
|
+
|
|
46
|
+
const stmt = program.stmts[0] as ImportDecl;
|
|
47
|
+
expect(stmt.items.length).toBe(3);
|
|
48
|
+
expect(stmt.items[0].name).toBe("add");
|
|
49
|
+
expect(stmt.items[1].name).toBe("subtract");
|
|
50
|
+
expect(stmt.items[2].name).toBe("multiply");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Test 3: Import alias
|
|
54
|
+
it("should parse import with alias", () => {
|
|
55
|
+
const code = `import { add as sum } from "./math";`;
|
|
56
|
+
const program = parseCode(code);
|
|
57
|
+
|
|
58
|
+
const stmt = program.stmts[0] as ImportDecl;
|
|
59
|
+
expect(stmt.items[0].name).toBe("add");
|
|
60
|
+
expect(stmt.items[0].alias).toBe("sum");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Test 4: Default import
|
|
64
|
+
it("should parse default import", () => {
|
|
65
|
+
const code = `import math from "./math";`;
|
|
66
|
+
const program = parseCode(code);
|
|
67
|
+
|
|
68
|
+
const stmt = program.stmts[0] as ImportDecl;
|
|
69
|
+
expect(stmt.default).toBe(true);
|
|
70
|
+
expect(stmt.items[0].name).toBe("math");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Test 5: Export with function
|
|
74
|
+
it("should parse export function", () => {
|
|
75
|
+
const code = `export fn add(a: i32, b: i32) -> i32 { a + b }`;
|
|
76
|
+
const program = parseCode(code);
|
|
77
|
+
|
|
78
|
+
const stmt = program.stmts[0] as ExportDecl;
|
|
79
|
+
expect(stmt.kind).toBe("export_decl");
|
|
80
|
+
expect(typeof stmt.target).not.toBe("string");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Test 6: Export with struct
|
|
84
|
+
it("should parse export struct", () => {
|
|
85
|
+
const code = `export struct Point { x: i32, y: i32 }`;
|
|
86
|
+
const program = parseCode(code);
|
|
87
|
+
|
|
88
|
+
const stmt = program.stmts[0] as ExportDecl;
|
|
89
|
+
expect(stmt.kind).toBe("export_decl");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Test 7: Export list
|
|
93
|
+
it("should parse export list", () => {
|
|
94
|
+
const code = `export { add, multiply, PI };`;
|
|
95
|
+
const program = parseCode(code);
|
|
96
|
+
|
|
97
|
+
const stmt = program.stmts[0] as ExportDecl;
|
|
98
|
+
expect(typeof stmt.target).toBe("object");
|
|
99
|
+
const names = stmt.target as string[];
|
|
100
|
+
expect(names.length).toBe(3);
|
|
101
|
+
expect(names[0]).toBe("add");
|
|
102
|
+
expect(names[1]).toBe("multiply");
|
|
103
|
+
expect(names[2]).toBe("PI");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Test 8: Type checking with imports
|
|
107
|
+
it("should check imported names in scope", () => {
|
|
108
|
+
const code = `
|
|
109
|
+
import { add } from "./math";
|
|
110
|
+
var result: i32 = add(2, 3);
|
|
111
|
+
`;
|
|
112
|
+
const program = parseCode(code);
|
|
113
|
+
const checker = new TypeChecker();
|
|
114
|
+
const errors = checker.check(program);
|
|
115
|
+
|
|
116
|
+
// import 문이 성공적으로 처리되어야 함
|
|
117
|
+
expect(errors.length).toBeLessThan(3); // 약간의 에러는 있을 수 있음 (모듈 미로드)
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Test 9: Multiple imports
|
|
121
|
+
it("should parse multiple import statements", () => {
|
|
122
|
+
const code = `
|
|
123
|
+
import { add } from "./math";
|
|
124
|
+
import { map, filter } from "./array";
|
|
125
|
+
fn main() -> void { }
|
|
126
|
+
`;
|
|
127
|
+
const program = parseCode(code);
|
|
128
|
+
|
|
129
|
+
expect(program.stmts[0].kind).toBe("import_decl");
|
|
130
|
+
expect(program.stmts[1].kind).toBe("import_decl");
|
|
131
|
+
expect(program.stmts[2].kind).toBe("fn_decl");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Test 10: Import and Export together
|
|
135
|
+
it("should parse import and export together", () => {
|
|
136
|
+
const code = `
|
|
137
|
+
import { double } from "./utils";
|
|
138
|
+
export fn quad(x: i32) -> i32 { double(double(x)) }
|
|
139
|
+
`;
|
|
140
|
+
const program = parseCode(code);
|
|
141
|
+
|
|
142
|
+
expect(program.stmts[0].kind).toBe("import_decl");
|
|
143
|
+
expect(program.stmts[1].kind).toBe("export_decl");
|
|
144
|
+
});
|
|
145
|
+
});
|