create-yukigo-parser 0.1.4 → 0.2.1
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/CHANGELOG.md +35 -23
- package/dist/index.js +0 -0
- package/package.json +2 -5
- package/src/index.ts +13 -13
- package/src/utils.ts +143 -143
- package/template/.mocharc.json +3 -3
- package/template/_package.json +35 -35
- package/template/src/grammar.ne +42 -42
- package/template/src/index.ts +44 -44
- package/template/src/lexer.ts +19 -19
- package/template/tests/parser.spec.ts +27 -27
- package/template/tsconfig.json +17 -17
- package/tsconfig.json +23 -23
package/CHANGELOG.md
CHANGED
|
@@ -1,31 +1,43 @@
|
|
|
1
|
-
## 0.1
|
|
1
|
+
## 0.2.1 (2026-08-01)
|
|
2
2
|
|
|
3
3
|
### 🧱 Updated Dependencies
|
|
4
4
|
|
|
5
|
-
- Updated yukigo-ast to 0.
|
|
5
|
+
- Updated yukigo-ast to 0.3.1
|
|
6
6
|
|
|
7
|
-
## 0.
|
|
7
|
+
## 0.2.0 (2026-08-01)
|
|
8
8
|
|
|
9
9
|
### 🧱 Updated Dependencies
|
|
10
10
|
|
|
11
|
-
- Updated yukigo-ast to 0.
|
|
12
|
-
|
|
13
|
-
## 0.1.
|
|
14
|
-
|
|
15
|
-
###
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
11
|
+
- Updated yukigo-ast to 0.3.0
|
|
12
|
+
|
|
13
|
+
## 0.1.4 (2026-05-01)
|
|
14
|
+
|
|
15
|
+
### 🧱 Updated Dependencies
|
|
16
|
+
|
|
17
|
+
- Updated yukigo-ast to 0.2.1
|
|
18
|
+
|
|
19
|
+
## 0.1.3 (2026-04-11)
|
|
20
|
+
|
|
21
|
+
### 🧱 Updated Dependencies
|
|
22
|
+
|
|
23
|
+
- Updated yukigo-ast to 0.2.0
|
|
24
|
+
|
|
25
|
+
## 0.1.1 (2025-12-09)
|
|
26
|
+
|
|
27
|
+
### 🚀 Features
|
|
28
|
+
|
|
29
|
+
- **LogicEngine:** Added LogicEngine with unification algorithm ([57b48a0](https://github.com/miyukiproject/yukigo/commit/57b48a0))
|
|
30
|
+
|
|
31
|
+
### ❤️ Thank You
|
|
32
|
+
|
|
33
|
+
- Valtolina Matias
|
|
34
|
+
|
|
35
|
+
## 0.1.0 (2025-12-09)
|
|
36
|
+
|
|
37
|
+
### 🚀 Features
|
|
38
|
+
|
|
39
|
+
- **LogicEngine:** Added LogicEngine with unification algorithm ([57b48a0](https://github.com/miyukiproject/yukigo/commit/57b48a0))
|
|
40
|
+
|
|
41
|
+
### ❤️ Thank You
|
|
42
|
+
|
|
31
43
|
- Valtolina Matias
|
package/dist/index.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-yukigo-parser",
|
|
3
3
|
"description": "A CLI to quickly set up a new Yukigo parser project.",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
@@ -18,13 +18,10 @@
|
|
|
18
18
|
"author": "noiseArch",
|
|
19
19
|
"license": "ISC",
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@types/
|
|
22
|
-
"ts-node": "^10.9.2",
|
|
23
|
-
"typescript": "^5.9.3"
|
|
21
|
+
"@types/fs-extra": "^11.0.4"
|
|
24
22
|
},
|
|
25
23
|
"dependencies": {
|
|
26
24
|
"@inquirer/prompts": "^7.9.0",
|
|
27
|
-
"@types/fs-extra": "^11.0.4",
|
|
28
25
|
"chalk": "^5.6.2",
|
|
29
26
|
"commander": "^14.0.2",
|
|
30
27
|
"fs-extra": "^11.3.2"
|
package/src/index.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
#! /usr/bin/env node
|
|
2
|
-
import { program } from "commander";
|
|
3
|
-
import { input } from "@inquirer/prompts";
|
|
4
|
-
import { createProject } from "./utils.js";
|
|
5
|
-
|
|
6
|
-
program
|
|
7
|
-
.version("1.0.0")
|
|
8
|
-
.description("An initializer for new yukigo parser projects.");
|
|
9
|
-
|
|
10
|
-
const name = await input({ message: `Project Name:` });
|
|
11
|
-
const projectName = `yukigo-${name}-parser`;
|
|
12
|
-
|
|
13
|
-
createProject(projectName);
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import { input } from "@inquirer/prompts";
|
|
4
|
+
import { createProject } from "./utils.js";
|
|
5
|
+
|
|
6
|
+
program
|
|
7
|
+
.version("1.0.0")
|
|
8
|
+
.description("An initializer for new yukigo parser projects.");
|
|
9
|
+
|
|
10
|
+
const name = await input({ message: `Project Name:` });
|
|
11
|
+
const projectName = `yukigo-${name}-parser`;
|
|
12
|
+
|
|
13
|
+
createProject(projectName);
|
package/src/utils.ts
CHANGED
|
@@ -1,143 +1,143 @@
|
|
|
1
|
-
import { confirm } from "@inquirer/prompts";
|
|
2
|
-
import chalk from "chalk";
|
|
3
|
-
import { execSync } from "child_process";
|
|
4
|
-
import { readdirSync } from "fs";
|
|
5
|
-
import fse from "fs-extra";
|
|
6
|
-
import path from "path";
|
|
7
|
-
|
|
8
|
-
const __dirname = import.meta.dirname;
|
|
9
|
-
const TEMPLATE_DIR = path.join(__dirname, "..", "template");
|
|
10
|
-
const INDEX_TEMPLATE_PATH = path.join("src", "index.ts");
|
|
11
|
-
const TEST_TEMPLATE_PATH = path.join("tests", "parser.spec.ts");
|
|
12
|
-
const CLASS_PLACEHOLDER = "YukigoParserPlaceholder";
|
|
13
|
-
|
|
14
|
-
export const runCommand = (
|
|
15
|
-
command: string,
|
|
16
|
-
cwd: string,
|
|
17
|
-
loadingMessage: string
|
|
18
|
-
) => {
|
|
19
|
-
try {
|
|
20
|
-
execSync(command, { stdio: "inherit", cwd });
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error(`\nFailed to execute command: ${command}`);
|
|
23
|
-
process.exit(1);
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export function isEmpty(path: string) {
|
|
28
|
-
return readdirSync(path).length === 0;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const toPascalCase = (str: string): string => {
|
|
32
|
-
let pascal = str
|
|
33
|
-
.toLowerCase()
|
|
34
|
-
.replace(/[^a-zA-Z0-9]+(.)/g, (match, chr) => chr.toUpperCase());
|
|
35
|
-
|
|
36
|
-
return pascal.charAt(0).toUpperCase() + pascal.slice(1);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export async function replaceInFile(
|
|
40
|
-
path: string,
|
|
41
|
-
search: string,
|
|
42
|
-
replace: string
|
|
43
|
-
) {
|
|
44
|
-
let content = await fse.readFile(path, "utf-8");
|
|
45
|
-
const regex = new RegExp(`${search}`, "g");
|
|
46
|
-
content = content.replace(regex, replace);
|
|
47
|
-
await fse.writeFile(path, content);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export const createProject = async (projectName: string) => {
|
|
51
|
-
const targetDir = path.resolve(projectName);
|
|
52
|
-
|
|
53
|
-
console.log(
|
|
54
|
-
`\n✨ Starting project setup for: ${chalk.bold.blue(projectName)}`
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
// Directory Validation
|
|
58
|
-
if (fse.existsSync(targetDir)) {
|
|
59
|
-
console.error(`\n❌ Error: Directory '${projectName}' already exists.`);
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Copy Template Files
|
|
64
|
-
console.log(`\n📁 Setting up project in ${targetDir}...`);
|
|
65
|
-
try {
|
|
66
|
-
await fse.copy(TEMPLATE_DIR, targetDir);
|
|
67
|
-
await fse.move(
|
|
68
|
-
path.join(targetDir, "_package.json"),
|
|
69
|
-
path.join(targetDir, "package.json")
|
|
70
|
-
);
|
|
71
|
-
} catch (error) {
|
|
72
|
-
console.error("\n❌ Failed to copy template files:", error);
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Update package.json
|
|
77
|
-
const packageJsonPath = path.join(targetDir, "package.json");
|
|
78
|
-
try {
|
|
79
|
-
const packageJson = await fse.readJson(packageJsonPath);
|
|
80
|
-
packageJson.name = projectName;
|
|
81
|
-
await fse.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
82
|
-
} catch (error) {
|
|
83
|
-
console.error("\n❌ Failed to update package.json:", error);
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const projectNamePascal = toPascalCase(projectName);
|
|
88
|
-
const templateIndexPath = path.join(targetDir, INDEX_TEMPLATE_PATH);
|
|
89
|
-
const templateTestPath = path.join(targetDir, TEST_TEMPLATE_PATH);
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
await replaceInFile(
|
|
93
|
-
templateIndexPath,
|
|
94
|
-
CLASS_PLACEHOLDER,
|
|
95
|
-
projectNamePascal
|
|
96
|
-
);
|
|
97
|
-
await replaceInFile(templateTestPath, CLASS_PLACEHOLDER, projectNamePascal);
|
|
98
|
-
} catch (error) {
|
|
99
|
-
console.error("\n❌ Failed to update class name:", error);
|
|
100
|
-
process.exit(1);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
console.log("✅ Initial project setted up correctly.");
|
|
104
|
-
|
|
105
|
-
// Initialize git if confirmed
|
|
106
|
-
const initGitRepo = await confirm({
|
|
107
|
-
message: `Do you want to initialize a git repository with the name '${projectName}'?`,
|
|
108
|
-
});
|
|
109
|
-
if (initGitRepo) {
|
|
110
|
-
runCommand("git init", targetDir, "\n🌱 Initializing Git repository...");
|
|
111
|
-
console.log("✅ Git repository initialized.");
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const runInstall = await confirm({
|
|
115
|
-
message: `Do you want to install dependencies automatically?`,
|
|
116
|
-
});
|
|
117
|
-
// install deps if confirmed
|
|
118
|
-
if (runInstall) {
|
|
119
|
-
runCommand(
|
|
120
|
-
"npm install",
|
|
121
|
-
targetDir,
|
|
122
|
-
"\n📦 Installing dependencies (this may take a minute)..."
|
|
123
|
-
);
|
|
124
|
-
console.log("✅ Dependencies installed.");
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// 6. Success Message
|
|
128
|
-
const successMsg = `${chalk.bold.green("Success!")} Project ${chalk.bold.blue(
|
|
129
|
-
projectName
|
|
130
|
-
)} is ready.`;
|
|
131
|
-
|
|
132
|
-
console.log("\n" + "-".repeat(successMsg.length));
|
|
133
|
-
console.log(successMsg);
|
|
134
|
-
console.log("-".repeat(successMsg.length));
|
|
135
|
-
console.log("\nNext steps:");
|
|
136
|
-
console.log(`1. ${chalk.bold(`cd ${projectName}`)}`);
|
|
137
|
-
console.log(
|
|
138
|
-
`2. Start coding: ${chalk.bold("npm start")} (or ${chalk.bold(
|
|
139
|
-
"npm run build"
|
|
140
|
-
)})`
|
|
141
|
-
);
|
|
142
|
-
console.log("\nHappy parsing! :)");
|
|
143
|
-
};
|
|
1
|
+
import { confirm } from "@inquirer/prompts";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { execSync } from "child_process";
|
|
4
|
+
import { readdirSync } from "fs";
|
|
5
|
+
import fse from "fs-extra";
|
|
6
|
+
import path from "path";
|
|
7
|
+
|
|
8
|
+
const __dirname = import.meta.dirname;
|
|
9
|
+
const TEMPLATE_DIR = path.join(__dirname, "..", "template");
|
|
10
|
+
const INDEX_TEMPLATE_PATH = path.join("src", "index.ts");
|
|
11
|
+
const TEST_TEMPLATE_PATH = path.join("tests", "parser.spec.ts");
|
|
12
|
+
const CLASS_PLACEHOLDER = "YukigoParserPlaceholder";
|
|
13
|
+
|
|
14
|
+
export const runCommand = (
|
|
15
|
+
command: string,
|
|
16
|
+
cwd: string,
|
|
17
|
+
loadingMessage: string
|
|
18
|
+
) => {
|
|
19
|
+
try {
|
|
20
|
+
execSync(command, { stdio: "inherit", cwd });
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error(`\nFailed to execute command: ${command}`);
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function isEmpty(path: string) {
|
|
28
|
+
return readdirSync(path).length === 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const toPascalCase = (str: string): string => {
|
|
32
|
+
let pascal = str
|
|
33
|
+
.toLowerCase()
|
|
34
|
+
.replace(/[^a-zA-Z0-9]+(.)/g, (match, chr) => chr.toUpperCase());
|
|
35
|
+
|
|
36
|
+
return pascal.charAt(0).toUpperCase() + pascal.slice(1);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export async function replaceInFile(
|
|
40
|
+
path: string,
|
|
41
|
+
search: string,
|
|
42
|
+
replace: string
|
|
43
|
+
) {
|
|
44
|
+
let content = await fse.readFile(path, "utf-8");
|
|
45
|
+
const regex = new RegExp(`${search}`, "g");
|
|
46
|
+
content = content.replace(regex, replace);
|
|
47
|
+
await fse.writeFile(path, content);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const createProject = async (projectName: string) => {
|
|
51
|
+
const targetDir = path.resolve(projectName);
|
|
52
|
+
|
|
53
|
+
console.log(
|
|
54
|
+
`\n✨ Starting project setup for: ${chalk.bold.blue(projectName)}`
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Directory Validation
|
|
58
|
+
if (fse.existsSync(targetDir)) {
|
|
59
|
+
console.error(`\n❌ Error: Directory '${projectName}' already exists.`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Copy Template Files
|
|
64
|
+
console.log(`\n📁 Setting up project in ${targetDir}...`);
|
|
65
|
+
try {
|
|
66
|
+
await fse.copy(TEMPLATE_DIR, targetDir);
|
|
67
|
+
await fse.move(
|
|
68
|
+
path.join(targetDir, "_package.json"),
|
|
69
|
+
path.join(targetDir, "package.json")
|
|
70
|
+
);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error("\n❌ Failed to copy template files:", error);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Update package.json
|
|
77
|
+
const packageJsonPath = path.join(targetDir, "package.json");
|
|
78
|
+
try {
|
|
79
|
+
const packageJson = await fse.readJson(packageJsonPath);
|
|
80
|
+
packageJson.name = projectName;
|
|
81
|
+
await fse.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error("\n❌ Failed to update package.json:", error);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const projectNamePascal = toPascalCase(projectName);
|
|
88
|
+
const templateIndexPath = path.join(targetDir, INDEX_TEMPLATE_PATH);
|
|
89
|
+
const templateTestPath = path.join(targetDir, TEST_TEMPLATE_PATH);
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
await replaceInFile(
|
|
93
|
+
templateIndexPath,
|
|
94
|
+
CLASS_PLACEHOLDER,
|
|
95
|
+
projectNamePascal
|
|
96
|
+
);
|
|
97
|
+
await replaceInFile(templateTestPath, CLASS_PLACEHOLDER, projectNamePascal);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error("\n❌ Failed to update class name:", error);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log("✅ Initial project setted up correctly.");
|
|
104
|
+
|
|
105
|
+
// Initialize git if confirmed
|
|
106
|
+
const initGitRepo = await confirm({
|
|
107
|
+
message: `Do you want to initialize a git repository with the name '${projectName}'?`,
|
|
108
|
+
});
|
|
109
|
+
if (initGitRepo) {
|
|
110
|
+
runCommand("git init", targetDir, "\n🌱 Initializing Git repository...");
|
|
111
|
+
console.log("✅ Git repository initialized.");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const runInstall = await confirm({
|
|
115
|
+
message: `Do you want to install dependencies automatically?`,
|
|
116
|
+
});
|
|
117
|
+
// install deps if confirmed
|
|
118
|
+
if (runInstall) {
|
|
119
|
+
runCommand(
|
|
120
|
+
"npm install",
|
|
121
|
+
targetDir,
|
|
122
|
+
"\n📦 Installing dependencies (this may take a minute)..."
|
|
123
|
+
);
|
|
124
|
+
console.log("✅ Dependencies installed.");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 6. Success Message
|
|
128
|
+
const successMsg = `${chalk.bold.green("Success!")} Project ${chalk.bold.blue(
|
|
129
|
+
projectName
|
|
130
|
+
)} is ready.`;
|
|
131
|
+
|
|
132
|
+
console.log("\n" + "-".repeat(successMsg.length));
|
|
133
|
+
console.log(successMsg);
|
|
134
|
+
console.log("-".repeat(successMsg.length));
|
|
135
|
+
console.log("\nNext steps:");
|
|
136
|
+
console.log(`1. ${chalk.bold(`cd ${projectName}`)}`);
|
|
137
|
+
console.log(
|
|
138
|
+
`2. Start coding: ${chalk.bold("npm start")} (or ${chalk.bold(
|
|
139
|
+
"npm run build"
|
|
140
|
+
)})`
|
|
141
|
+
);
|
|
142
|
+
console.log("\nHappy parsing! :)");
|
|
143
|
+
};
|
package/template/.mocharc.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{
|
|
2
|
-
"extension": ["ts"],
|
|
3
|
-
"spec": "tests/**/*.spec.ts"
|
|
1
|
+
{
|
|
2
|
+
"extension": ["ts"],
|
|
3
|
+
"spec": "tests/**/*.spec.ts"
|
|
4
4
|
}
|
package/template/_package.json
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "yukigo-parser",
|
|
3
|
-
"version": "1.0.0",
|
|
4
|
-
"description": "",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.js",
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"exports": {
|
|
9
|
-
".": "./dist/index.js",
|
|
10
|
-
"./package.json": "./package.json"
|
|
11
|
-
},
|
|
12
|
-
"scripts": {
|
|
13
|
-
"grammar": "nearleyc ./src/grammar.ne -o ./src/grammar.ts",
|
|
14
|
-
"build": "npm run grammar && tsc",
|
|
15
|
-
"test": "npm run build && mocha --import=tsx"
|
|
16
|
-
},
|
|
17
|
-
"keywords": [],
|
|
18
|
-
"author": "",
|
|
19
|
-
"license": "ISC",
|
|
20
|
-
"devDependencies": {
|
|
21
|
-
"@types/chai": "^5.2.2",
|
|
22
|
-
"@types/mocha": "^10.0.10",
|
|
23
|
-
"@types/moo": "^0.5.10",
|
|
24
|
-
"@types/node": "^24.2.0",
|
|
25
|
-
"chai": "^5.2.1",
|
|
26
|
-
"mocha": "^11.7.1",
|
|
27
|
-
"tsx": "^4.20.6",
|
|
28
|
-
"typescript": "^5.9.2"
|
|
29
|
-
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"moo": "^0.5.2",
|
|
32
|
-
"nearley": "^2.20.1",
|
|
33
|
-
"yukigo-ast": "latest"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "yukigo-parser",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"grammar": "nearleyc ./src/grammar.ne -o ./src/grammar.ts",
|
|
14
|
+
"build": "npm run grammar && tsc",
|
|
15
|
+
"test": "npm run build && mocha --import=tsx"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [],
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "ISC",
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/chai": "^5.2.2",
|
|
22
|
+
"@types/mocha": "^10.0.10",
|
|
23
|
+
"@types/moo": "^0.5.10",
|
|
24
|
+
"@types/node": "^24.2.0",
|
|
25
|
+
"chai": "^5.2.1",
|
|
26
|
+
"mocha": "^11.7.1",
|
|
27
|
+
"tsx": "^4.20.6",
|
|
28
|
+
"typescript": "^5.9.2"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"moo": "^0.5.2",
|
|
32
|
+
"nearley": "^2.20.1",
|
|
33
|
+
"yukigo-ast": "latest"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/template/src/grammar.ne
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
@{%
|
|
2
|
-
import { Lexer } from "./lexer.js"
|
|
3
|
-
import {
|
|
4
|
-
SourceLocation,
|
|
5
|
-
ArithmeticBinaryOperation,
|
|
6
|
-
Return,
|
|
7
|
-
NumberPrimitive,
|
|
8
|
-
StringPrimitive,
|
|
9
|
-
SymbolPrimitive,
|
|
10
|
-
CharPrimitive,
|
|
11
|
-
BooleanPrimitive
|
|
12
|
-
} from "yukigo-ast"
|
|
13
|
-
|
|
14
|
-
const loc = (token) => new SourceLocation(token.line, token.col);
|
|
15
|
-
|
|
16
|
-
%}
|
|
17
|
-
@preprocessor typescript
|
|
18
|
-
@lexer Lexer
|
|
19
|
-
|
|
20
|
-
program -> addition {% (d) => [new Return(d[0])] %}
|
|
21
|
-
|
|
22
|
-
addition ->
|
|
23
|
-
addition _ "+" _ multiplication {% (d) => new ArithmeticBinaryOperation("Plus", d[0], d[4]) %}
|
|
24
|
-
| addition _ "-" _ multiplication {% (d) => new ArithmeticBinaryOperation("Minus", d[0], d[4]) %}
|
|
25
|
-
| multiplication {% id %}
|
|
26
|
-
|
|
27
|
-
# priority 7
|
|
28
|
-
multiplication ->
|
|
29
|
-
multiplication _ "*" _ primitive {% (d) => new ArithmeticBinaryOperation("Multiply", d[0], d[4]) %}
|
|
30
|
-
| multiplication _ "/" _ primitive {% (d) => new ArithmeticBinaryOperation("Divide", d[0], d[4]) %}
|
|
31
|
-
| primitive {% id %}
|
|
32
|
-
|
|
33
|
-
primitive ->
|
|
34
|
-
%number {% ([n]) => new NumberPrimitive(Number(n.value), loc(n)) %}
|
|
35
|
-
| %char {% ([c]) => new CharPrimitive(c.value, loc(c)) %}
|
|
36
|
-
| %variable {% ([c]) => new SymbolPrimitive(c.value, loc(c)) %}
|
|
37
|
-
| %string {% ([s]) => new StringPrimitive(s.value.slice(1, -1), loc(s)) %}
|
|
38
|
-
| %bool {% ([b]) => new BooleanPrimitive(b.value === 'True' ? true : false, loc(b)) %}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
_ -> %WS:*
|
|
42
|
-
|
|
1
|
+
@{%
|
|
2
|
+
import { Lexer } from "./lexer.js"
|
|
3
|
+
import {
|
|
4
|
+
SourceLocation,
|
|
5
|
+
ArithmeticBinaryOperation,
|
|
6
|
+
Return,
|
|
7
|
+
NumberPrimitive,
|
|
8
|
+
StringPrimitive,
|
|
9
|
+
SymbolPrimitive,
|
|
10
|
+
CharPrimitive,
|
|
11
|
+
BooleanPrimitive
|
|
12
|
+
} from "yukigo-ast"
|
|
13
|
+
|
|
14
|
+
const loc = (token) => new SourceLocation(token.line, token.col);
|
|
15
|
+
|
|
16
|
+
%}
|
|
17
|
+
@preprocessor typescript
|
|
18
|
+
@lexer Lexer
|
|
19
|
+
|
|
20
|
+
program -> addition {% (d) => [new Return(d[0])] %}
|
|
21
|
+
|
|
22
|
+
addition ->
|
|
23
|
+
addition _ "+" _ multiplication {% (d) => new ArithmeticBinaryOperation("Plus", d[0], d[4]) %}
|
|
24
|
+
| addition _ "-" _ multiplication {% (d) => new ArithmeticBinaryOperation("Minus", d[0], d[4]) %}
|
|
25
|
+
| multiplication {% id %}
|
|
26
|
+
|
|
27
|
+
# priority 7
|
|
28
|
+
multiplication ->
|
|
29
|
+
multiplication _ "*" _ primitive {% (d) => new ArithmeticBinaryOperation("Multiply", d[0], d[4]) %}
|
|
30
|
+
| multiplication _ "/" _ primitive {% (d) => new ArithmeticBinaryOperation("Divide", d[0], d[4]) %}
|
|
31
|
+
| primitive {% id %}
|
|
32
|
+
|
|
33
|
+
primitive ->
|
|
34
|
+
%number {% ([n]) => new NumberPrimitive(Number(n.value), loc(n)) %}
|
|
35
|
+
| %char {% ([c]) => new CharPrimitive(c.value, loc(c)) %}
|
|
36
|
+
| %variable {% ([c]) => new SymbolPrimitive(c.value, loc(c)) %}
|
|
37
|
+
| %string {% ([s]) => new StringPrimitive(s.value.slice(1, -1), loc(s)) %}
|
|
38
|
+
| %bool {% ([b]) => new BooleanPrimitive(b.value === 'True' ? true : false, loc(b)) %}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
_ -> %WS:*
|
|
42
|
+
|
|
43
43
|
__ -> %WS:+
|
package/template/src/index.ts
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import grammar from "./grammar.js";
|
|
2
|
-
import nearley from "nearley";
|
|
3
|
-
import { AST, Expression, YukigoParser } from "yukigo-ast";
|
|
4
|
-
|
|
5
|
-
export class YukigoParserPlaceholder implements YukigoParser {
|
|
6
|
-
public errors: string[] = [];
|
|
7
|
-
constructor() {
|
|
8
|
-
this.errors = [];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
public parse(code: string): AST {
|
|
12
|
-
return this.feedParser(code);
|
|
13
|
-
}
|
|
14
|
-
public parseExpression(code: string): Expression {
|
|
15
|
-
return this.feedParser(code);
|
|
16
|
-
}
|
|
17
|
-
private feedParser(code: string) {
|
|
18
|
-
const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));
|
|
19
|
-
try {
|
|
20
|
-
parser.feed(code);
|
|
21
|
-
parser.finish();
|
|
22
|
-
} catch (error) {
|
|
23
|
-
console.log(error);
|
|
24
|
-
if ("token" in error) {
|
|
25
|
-
const token = error.token;
|
|
26
|
-
const message = `Parser: Unexpected '${token.type}' token '${token.value}' at line ${token.line} col ${token.col}.`;
|
|
27
|
-
this.errors.push(message);
|
|
28
|
-
throw Error(message);
|
|
29
|
-
}
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
if (parser.results.length > 1) {
|
|
33
|
-
const msg = `Parser: Too much ambiguity. ${parser.results.length} ASTs parsed. Output not generated.`;
|
|
34
|
-
this.errors.push(msg);
|
|
35
|
-
throw Error(msg);
|
|
36
|
-
}
|
|
37
|
-
if (parser.results.length == 0) {
|
|
38
|
-
this.errors.push("Parser did not generate an AST.");
|
|
39
|
-
throw Error("Parser did not generate an AST.");
|
|
40
|
-
}
|
|
41
|
-
const ast = parser.results[0];
|
|
42
|
-
return ast;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
import grammar from "./grammar.js";
|
|
2
|
+
import nearley from "nearley";
|
|
3
|
+
import { AST, Expression, YukigoParser } from "yukigo-ast";
|
|
4
|
+
|
|
5
|
+
export class YukigoParserPlaceholder implements YukigoParser {
|
|
6
|
+
public errors: string[] = [];
|
|
7
|
+
constructor() {
|
|
8
|
+
this.errors = [];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public parse(code: string): AST {
|
|
12
|
+
return this.feedParser(code);
|
|
13
|
+
}
|
|
14
|
+
public parseExpression(code: string): Expression {
|
|
15
|
+
return this.feedParser(code);
|
|
16
|
+
}
|
|
17
|
+
private feedParser(code: string) {
|
|
18
|
+
const parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));
|
|
19
|
+
try {
|
|
20
|
+
parser.feed(code);
|
|
21
|
+
parser.finish();
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.log(error);
|
|
24
|
+
if ("token" in error) {
|
|
25
|
+
const token = error.token;
|
|
26
|
+
const message = `Parser: Unexpected '${token.type}' token '${token.value}' at line ${token.line} col ${token.col}.`;
|
|
27
|
+
this.errors.push(message);
|
|
28
|
+
throw Error(message);
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
if (parser.results.length > 1) {
|
|
33
|
+
const msg = `Parser: Too much ambiguity. ${parser.results.length} ASTs parsed. Output not generated.`;
|
|
34
|
+
this.errors.push(msg);
|
|
35
|
+
throw Error(msg);
|
|
36
|
+
}
|
|
37
|
+
if (parser.results.length == 0) {
|
|
38
|
+
this.errors.push("Parser did not generate an AST.");
|
|
39
|
+
throw Error("Parser did not generate an AST.");
|
|
40
|
+
}
|
|
41
|
+
const ast = parser.results[0];
|
|
42
|
+
return ast;
|
|
43
|
+
}
|
|
44
|
+
}
|
package/template/src/lexer.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import moo from "moo";
|
|
2
|
-
|
|
3
|
-
export const LexerConfig = {
|
|
4
|
-
NL: { match: /\r?\n/, lineBreaks: true },
|
|
5
|
-
WS: / |\t/,
|
|
6
|
-
number:
|
|
7
|
-
/0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:\d*\.\d+|\d+)(?:[eE][+-]?\d+)?/,
|
|
8
|
-
char: /'(?:\\['\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^'\\\n\r])?'/,
|
|
9
|
-
string: /"(?:\\["\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^"\\\n\r])*"/,
|
|
10
|
-
bool: {
|
|
11
|
-
match: ["True", "False"],
|
|
12
|
-
},
|
|
13
|
-
op: /\+|-|\*|\//,
|
|
14
|
-
variable: {
|
|
15
|
-
match: /[a-z_][a-zA-Z0-9_']*/,
|
|
16
|
-
},
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export const Lexer = moo.compile(LexerConfig);
|
|
1
|
+
import moo from "moo";
|
|
2
|
+
|
|
3
|
+
export const LexerConfig = {
|
|
4
|
+
NL: { match: /\r?\n/, lineBreaks: true },
|
|
5
|
+
WS: / |\t/,
|
|
6
|
+
number:
|
|
7
|
+
/0[xX][0-9a-fA-F]+|0[bB][01]+|0[oO][0-7]+|(?:\d*\.\d+|\d+)(?:[eE][+-]?\d+)?/,
|
|
8
|
+
char: /'(?:\\['\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^'\\\n\r])?'/,
|
|
9
|
+
string: /"(?:\\["\\bfnrtv0]|\\u[0-9a-fA-F]{4}|[^"\\\n\r])*"/,
|
|
10
|
+
bool: {
|
|
11
|
+
match: ["True", "False"],
|
|
12
|
+
},
|
|
13
|
+
op: /\+|-|\*|\//,
|
|
14
|
+
variable: {
|
|
15
|
+
match: /[a-z_][a-zA-Z0-9_']*/,
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const Lexer = moo.compile(LexerConfig);
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { YukigoParserPlaceholder } from "../src/index.js";
|
|
2
|
-
import {
|
|
3
|
-
ArithmeticBinaryOperation,
|
|
4
|
-
NumberPrimitive,
|
|
5
|
-
YukigoParser,
|
|
6
|
-
Return,
|
|
7
|
-
SourceLocation,
|
|
8
|
-
} from "yukigo-ast";
|
|
9
|
-
import { assert } from "chai";
|
|
10
|
-
|
|
11
|
-
describe("Parser Tests", () => {
|
|
12
|
-
let parser: YukigoParser;
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
parser = new YukigoParserPlaceholder();
|
|
15
|
-
});
|
|
16
|
-
it("parses basic sum", () => {
|
|
17
|
-
assert.deepEqual(parser.parse("1 + 2"), [
|
|
18
|
-
new Return(
|
|
19
|
-
new ArithmeticBinaryOperation(
|
|
20
|
-
"Plus",
|
|
21
|
-
new NumberPrimitive(1, new SourceLocation(1, 1)),
|
|
22
|
-
new NumberPrimitive(2, new SourceLocation(1, 5))
|
|
23
|
-
)
|
|
24
|
-
),
|
|
25
|
-
]);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
1
|
+
import { YukigoParserPlaceholder } from "../src/index.js";
|
|
2
|
+
import {
|
|
3
|
+
ArithmeticBinaryOperation,
|
|
4
|
+
NumberPrimitive,
|
|
5
|
+
YukigoParser,
|
|
6
|
+
Return,
|
|
7
|
+
SourceLocation,
|
|
8
|
+
} from "yukigo-ast";
|
|
9
|
+
import { assert } from "chai";
|
|
10
|
+
|
|
11
|
+
describe("Parser Tests", () => {
|
|
12
|
+
let parser: YukigoParser;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
parser = new YukigoParserPlaceholder();
|
|
15
|
+
});
|
|
16
|
+
it("parses basic sum", () => {
|
|
17
|
+
assert.deepEqual(parser.parse("1 + 2"), [
|
|
18
|
+
new Return(
|
|
19
|
+
new ArithmeticBinaryOperation(
|
|
20
|
+
"Plus",
|
|
21
|
+
new NumberPrimitive(1, new SourceLocation(1, 1)),
|
|
22
|
+
new NumberPrimitive(2, new SourceLocation(1, 5))
|
|
23
|
+
)
|
|
24
|
+
),
|
|
25
|
+
]);
|
|
26
|
+
});
|
|
27
|
+
});
|
package/template/tsconfig.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2024",
|
|
4
|
-
"module": "nodenext",
|
|
5
|
-
"moduleResolution": "nodenext",
|
|
6
|
-
"lib": ["ES2024"],
|
|
7
|
-
"outDir": "./dist",
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"allowSyntheticDefaultImports": true,
|
|
11
|
-
"sourceMap": true,
|
|
12
|
-
"forceConsistentCasingInFileNames": true,
|
|
13
|
-
"skipLibCheck": true
|
|
14
|
-
},
|
|
15
|
-
"include": ["src"],
|
|
16
|
-
"exclude": ["dist/**/*"]
|
|
17
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2024",
|
|
4
|
+
"module": "nodenext",
|
|
5
|
+
"moduleResolution": "nodenext",
|
|
6
|
+
"lib": ["ES2024"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"allowSyntheticDefaultImports": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"skipLibCheck": true
|
|
14
|
+
},
|
|
15
|
+
"include": ["src"],
|
|
16
|
+
"exclude": ["dist/**/*"]
|
|
17
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"rootDir": "./src",
|
|
4
|
-
"outDir": "./dist",
|
|
5
|
-
"module": "nodenext",
|
|
6
|
-
"target": "es2024",
|
|
7
|
-
"types": ["node"],
|
|
8
|
-
"lib": ["ES2024"],
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"skipLibCheck": true
|
|
13
|
-
},
|
|
14
|
-
"exclude": ["template", "dist"],
|
|
15
|
-
"include": [
|
|
16
|
-
"src"
|
|
17
|
-
],
|
|
18
|
-
"references": [
|
|
19
|
-
{
|
|
20
|
-
"path": "../yukigo-ast"
|
|
21
|
-
}
|
|
22
|
-
]
|
|
23
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"rootDir": "./src",
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"module": "nodenext",
|
|
6
|
+
"target": "es2024",
|
|
7
|
+
"types": ["node"],
|
|
8
|
+
"lib": ["ES2024"],
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"skipLibCheck": true
|
|
13
|
+
},
|
|
14
|
+
"exclude": ["template", "dist"],
|
|
15
|
+
"include": [
|
|
16
|
+
"src"
|
|
17
|
+
],
|
|
18
|
+
"references": [
|
|
19
|
+
{
|
|
20
|
+
"path": "../yukigo-ast"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|