Skip to content

Commit ec30714

Browse files
committed
copy command-line/ from inet-js
1 parent 3058205 commit ec30714

File tree

11 files changed

+222
-1
lines changed

11 files changed

+222
-1
lines changed

TODO.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
copy command-line/ from inet-js
21
setup the `run` command
32

43
# net

src/command-line/commands/Default.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { Command, CommandRunner } from "@xieyuheng/command-line"
2+
import { ty } from "@xieyuheng/ty"
3+
import { app } from "../../app/index"
4+
import * as Commands from "../commands"
5+
6+
type Args = { path?: string }
7+
type Opts = { help?: boolean; version?: boolean }
8+
9+
export class Default extends Command<Args, Opts> {
10+
name = "default"
11+
12+
description = "Run a file"
13+
14+
args = { path: ty.optional(ty.string()) }
15+
opts = {
16+
help: ty.optional(ty.boolean()),
17+
version: ty.optional(ty.boolean()),
18+
}
19+
alias = { help: ["h"], version: ["v"] }
20+
21+
async execute(argv: Args & Opts, runner: CommandRunner): Promise<void> {
22+
if (argv["help"]) {
23+
const command = new Commands.CommonHelp()
24+
await command.execute({}, runner)
25+
return
26+
}
27+
28+
if (argv["version"]) {
29+
console.log(app.config.packageJson.version)
30+
return
31+
}
32+
33+
const path = argv["path"]
34+
35+
if (path === undefined) {
36+
// const dir = process.cwd()
37+
// const command = new Commands.Repl()
38+
// await command.execute({ dir })
39+
} else {
40+
const command = new Commands.Run()
41+
await command.execute({ path })
42+
}
43+
}
44+
}

src/command-line/commands/Run.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { ParsingError } from "@cicada-lang/partech/lib/errors"
2+
import { Command, CommandRunner } from "@xieyuheng/command-line"
3+
import { ty } from "@xieyuheng/ty"
4+
import fs from "node:fs"
5+
import { relative } from "node:path"
6+
import process from "node:process"
7+
import { Fetcher } from "../../fetcher"
8+
import { Report } from "../../lang/errors/Report"
9+
import { Loader } from "../../loader"
10+
import { createURL } from "../../utils/createURL"
11+
12+
type Args = { path: string }
13+
type Opts = {}
14+
15+
export class Run extends Command<Args, Opts> {
16+
name = "run"
17+
18+
description = "Run an inet program"
19+
20+
args = { path: ty.string() }
21+
22+
// prettier-ignore
23+
help(runner: CommandRunner): string {
24+
const { blue } = this.colors
25+
26+
return [
27+
`Run a file:`,
28+
``,
29+
blue(` ${runner.name} ${this.name} std/datatype/Nat.test.i`),
30+
``,
31+
`Run a URL:`,
32+
``,
33+
blue(` ${runner.name} ${this.name} https://code-of-inet.fidb.app/std/datatype/Nat.test.i`),
34+
35+
``,
36+
].join("\n")
37+
}
38+
39+
async execute(argv: Args & Opts): Promise<void> {
40+
const fetcher = new Fetcher()
41+
42+
fetcher.register("file", {
43+
async fetchText(url) {
44+
if (process.platform === "win32") {
45+
return await fs.promises.readFile(url.pathname.slice(1), "utf8")
46+
} else {
47+
return await fs.promises.readFile(url.pathname, "utf8")
48+
}
49+
},
50+
51+
formatURL(url) {
52+
if (process.platform === "win32") {
53+
return relative(process.cwd(), url.pathname.slice(1)).replaceAll(
54+
"\\",
55+
"/",
56+
)
57+
} else {
58+
return relative(process.cwd(), url.pathname)
59+
}
60+
},
61+
})
62+
63+
const url = createURL(argv.path)
64+
const text = await fetcher.fetchText(url)
65+
66+
try {
67+
const loader = new Loader({ fetcher })
68+
await loader.load(url)
69+
} catch (error) {
70+
if (error instanceof ParsingError) {
71+
console.error(error.report(text))
72+
process.exit(1)
73+
} else if (error instanceof Report) {
74+
console.error(error.format())
75+
process.exit(1)
76+
} else {
77+
throw error
78+
}
79+
}
80+
}
81+
}

src/command-line/commands/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export * from "@xieyuheng/command-line/lib/commands"
2+
export * from "./Default"
3+
// export * from "./Format"
4+
// export * from "./Parse"
5+
// export * from "./Repl"
6+
export * from "./Run"

src/command-line/index.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { CommandRunner, CommandRunners } from "@xieyuheng/command-line"
2+
import * as Commands from "./commands"
3+
4+
export function createCommandRunner(): CommandRunner {
5+
return new CommandRunners.CommonCommandRunner({
6+
defaultCommand: new Commands.Default(),
7+
commands: [
8+
// new Commands.Repl(),
9+
new Commands.Run(),
10+
// new Commands.Parse(),
11+
// new Commands.Format(),
12+
new Commands.CommonHelp(),
13+
],
14+
})
15+
}

src/lang/errors/ParsingError.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { ParsingError } from "@cicada-lang/partech/lib/errors"

src/lang/errors/Report.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import * as pt from "@cicada-lang/partech"
2+
import { Span } from "../span"
3+
4+
export type ReportEntry = {
5+
message: string
6+
context?: {
7+
span: Span
8+
text: string
9+
}
10+
}
11+
12+
export class Report extends Error {
13+
constructor(public entries: Array<ReportEntry> = []) {
14+
super()
15+
}
16+
17+
format(): string {
18+
return this.entries
19+
.map(formatReportEntry)
20+
.map((s) => s.trim())
21+
.join("\n\n")
22+
}
23+
24+
get message(): string {
25+
return this.format()
26+
}
27+
}
28+
29+
function formatReportEntry(entry: ReportEntry): string {
30+
if (entry.context === undefined) {
31+
return entry.message
32+
} else {
33+
return [
34+
entry.message,
35+
"",
36+
pt.report(entry.context.span, entry.context.text),
37+
].join("\n")
38+
}
39+
}

src/lang/errors/appendReport.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Report, ReportEntry } from "./Report"
2+
import { createReportEntry } from "./createReportEntry"
3+
4+
export function appendReport(error: unknown, entry: ReportEntry): Report {
5+
// NOTE We put the most recent report entry at the end,
6+
// because the end is closer to user's terminal output.
7+
8+
if (error instanceof Report) {
9+
error.entries.push(entry)
10+
return error
11+
}
12+
13+
return new Report([createReportEntry(error), entry])
14+
}

src/lang/errors/createReport.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { Report, ReportEntry } from "./Report"
2+
3+
export function createReport(entry: ReportEntry): Report {
4+
return new Report([entry])
5+
}

src/lang/errors/createReportEntry.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { ReportEntry } from "./Report"
2+
3+
export function createReportEntry(error: unknown): ReportEntry {
4+
if (error instanceof Error) {
5+
return {
6+
message: error.message,
7+
}
8+
} else {
9+
return {
10+
message: String(error),
11+
}
12+
}
13+
}

0 commit comments

Comments
 (0)