@jpetit/toolkit 3.1.1 → 3.1.2
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/lib/ai.ts +200 -0
- package/lib/cleaner.ts +77 -0
- package/lib/compilers/base.ts +159 -0
- package/lib/compilers/clojure.ts +87 -0
- package/lib/compilers/gcc.ts +39 -0
- package/lib/compilers/ghc.ts +39 -0
- package/lib/compilers/gxx.ts +39 -0
- package/lib/compilers/index.ts +81 -0
- package/lib/compilers/java.ts +105 -0
- package/lib/compilers/python3.ts +112 -0
- package/lib/compilers/run-clojure.ts +101 -0
- package/lib/compilers/run-haskell.ts +117 -0
- package/lib/compilers/run-python.ts +103 -0
- package/lib/compilers/rust.ts +39 -0
- package/lib/create-with-jutgeai.ts +407 -0
- package/lib/create-with-template.ts +55 -0
- package/lib/data.ts +25 -0
- package/lib/doctor.ts +238 -0
- package/lib/generate.ts +171 -0
- package/lib/helpers.ts +48 -0
- package/lib/inspector.ts +253 -0
- package/lib/jutge_api_client.ts +4631 -0
- package/lib/maker.ts +613 -0
- package/lib/settings.ts +51 -0
- package/lib/tui.ts +152 -0
- package/lib/types.ts +55 -0
- package/lib/upload.ts +216 -0
- package/lib/utils.ts +201 -0
- package/lib/versions.ts +46 -0
- package/package.json +4 -2
- package/toolkit/about.ts +43 -0
- package/toolkit/ai.ts +56 -0
- package/toolkit/check.ts +16 -0
- package/toolkit/clean.ts +27 -0
- package/toolkit/compilers.ts +29 -0
- package/toolkit/config.ts +91 -0
- package/toolkit/create.ts +37 -0
- package/toolkit/doctor.ts +22 -0
- package/toolkit/generate.ts +213 -0
- package/toolkit/make.ts +82 -0
- package/toolkit/upgrade.ts +9 -0
- package/toolkit/upload.ts +19 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { nothing } from '../utils'
|
|
2
|
+
import { Compiler, type CompilerInfo } from './base'
|
|
3
|
+
import { GCC_Compiler } from './gcc'
|
|
4
|
+
import { GXX_Compiler } from './gxx'
|
|
5
|
+
import { Python3_Compiler } from './python3'
|
|
6
|
+
import { GHC_Compiler } from './ghc'
|
|
7
|
+
import { Clojure_Compiler } from './clojure'
|
|
8
|
+
import { Java_Compiler } from './java'
|
|
9
|
+
import { Rust_Compiler } from './rust'
|
|
10
|
+
import { RunPython_Compiler } from './run-python'
|
|
11
|
+
import { RunHaskell_Compiler } from './run-haskell'
|
|
12
|
+
import { RunClojure_Compiler } from './run-clojure'
|
|
13
|
+
|
|
14
|
+
const compilersRegistryById: Record<string, new () => Compiler> = {
|
|
15
|
+
C: GCC_Compiler,
|
|
16
|
+
'C++': GXX_Compiler,
|
|
17
|
+
Python3: Python3_Compiler,
|
|
18
|
+
Haskell: GHC_Compiler,
|
|
19
|
+
Clojure: Clojure_Compiler,
|
|
20
|
+
Java: Java_Compiler,
|
|
21
|
+
Rust: Rust_Compiler,
|
|
22
|
+
|
|
23
|
+
RunPython: RunPython_Compiler,
|
|
24
|
+
RunHaskell: RunHaskell_Compiler,
|
|
25
|
+
RunClojure: RunClojure_Compiler,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const compilersRegistryByExtension: Record<string, new () => Compiler> = {
|
|
29
|
+
c: GCC_Compiler,
|
|
30
|
+
cc: GXX_Compiler,
|
|
31
|
+
py: Python3_Compiler,
|
|
32
|
+
hs: GHC_Compiler,
|
|
33
|
+
clj: Clojure_Compiler,
|
|
34
|
+
java: Java_Compiler,
|
|
35
|
+
rs: Rust_Compiler,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function getCompilerById(id: string): Compiler {
|
|
39
|
+
const CompilerClass = compilersRegistryById[id]
|
|
40
|
+
if (!CompilerClass) throw new Error(`Compiler '${id}' is not defined`)
|
|
41
|
+
const compilerInstance = new CompilerClass()
|
|
42
|
+
return compilerInstance
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getCompilerByExtension(extension: string): Compiler {
|
|
46
|
+
const CompilerClass = compilersRegistryByExtension[extension]
|
|
47
|
+
if (!CompilerClass) throw new Error(`No compiler defined for extension '.${extension}'`)
|
|
48
|
+
const compilerInstance = new CompilerClass()
|
|
49
|
+
return compilerInstance
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function getDefinedCompilerIds(): Promise<string[]> {
|
|
53
|
+
await nothing()
|
|
54
|
+
return Object.keys(compilersRegistryById)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function getAvailableCompilers(): Promise<string[]> {
|
|
58
|
+
const available: string[] = []
|
|
59
|
+
for (const id of Object.keys(compilersRegistryById)) {
|
|
60
|
+
const CompilerClass = compilersRegistryById[id]!
|
|
61
|
+
const compilerInstance = new CompilerClass()
|
|
62
|
+
if (await compilerInstance.available()) {
|
|
63
|
+
available.push(id)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return available
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export async function getCompilerInfo(id: string): Promise<CompilerInfo> {
|
|
70
|
+
const compilerInstance = getCompilerById(id)
|
|
71
|
+
if (!compilerInstance) throw new Error(`Compiler '${id}' is not defined`)
|
|
72
|
+
return await compilerInstance.info()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function getCompilersInfo(): Promise<Record<string, CompilerInfo>> {
|
|
76
|
+
const infos: Record<string, CompilerInfo> = {}
|
|
77
|
+
for (const id of Object.keys(compilersRegistryById)) {
|
|
78
|
+
infos[id] = await getCompilerInfo(id)
|
|
79
|
+
}
|
|
80
|
+
return infos
|
|
81
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { execa } from 'execa'
|
|
2
|
+
import { join, parse } from 'path'
|
|
3
|
+
import tui from '../tui'
|
|
4
|
+
import type { Handler } from '../types'
|
|
5
|
+
import { nothing, toolkitPrefix } from '../utils'
|
|
6
|
+
import { Compiler } from './base'
|
|
7
|
+
|
|
8
|
+
export class Java_Compiler extends Compiler {
|
|
9
|
+
id(): string {
|
|
10
|
+
return 'Java'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
name(): string {
|
|
14
|
+
return 'Java'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type(): string {
|
|
18
|
+
return 'vm'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
language(): string {
|
|
22
|
+
return 'Java'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async version(): Promise<string> {
|
|
26
|
+
return await this.getVersion('javac --version', 0)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
flags1(): string {
|
|
30
|
+
return ''
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
flags2(): string {
|
|
34
|
+
return ''
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
tool(): string {
|
|
38
|
+
return 'javac'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
extension(): string {
|
|
42
|
+
return 'java'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override async compileNormal(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
46
|
+
const classPath = 'Main.class'
|
|
47
|
+
|
|
48
|
+
await this.rmInDir(directory, classPath)
|
|
49
|
+
|
|
50
|
+
tui.command(`${this.tool()} ${sourcePath}`)
|
|
51
|
+
await execa({
|
|
52
|
+
reject: false,
|
|
53
|
+
stderr: 'inherit',
|
|
54
|
+
stdout: 'inherit',
|
|
55
|
+
cwd: directory,
|
|
56
|
+
})`${this.tool()} ${sourcePath}`
|
|
57
|
+
|
|
58
|
+
return classPath
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
override async compileWithMain(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
62
|
+
const classPath = 'Main.class'
|
|
63
|
+
|
|
64
|
+
tui.command(`add main.${this.extension()} to ${sourcePath}`)
|
|
65
|
+
await this.concatText(directory, [`main.${this.extension()}`, sourcePath], sourcePath)
|
|
66
|
+
|
|
67
|
+
await this.rmInDir(directory, classPath)
|
|
68
|
+
|
|
69
|
+
tui.command(`${this.tool()} ${sourcePath}`)
|
|
70
|
+
await execa({
|
|
71
|
+
reject: false,
|
|
72
|
+
stderr: 'inherit',
|
|
73
|
+
stdout: 'inherit',
|
|
74
|
+
cwd: directory,
|
|
75
|
+
})`${this.tool()} ${sourcePath}`
|
|
76
|
+
|
|
77
|
+
return classPath
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
override async execute(
|
|
81
|
+
handler: Handler,
|
|
82
|
+
directory: string,
|
|
83
|
+
sourcePath: string,
|
|
84
|
+
inputPath: string,
|
|
85
|
+
outputPath: string,
|
|
86
|
+
): Promise<void> {
|
|
87
|
+
const className = 'Main'
|
|
88
|
+
const classPath = className + '.class'
|
|
89
|
+
|
|
90
|
+
await this.rmInDir(directory, outputPath)
|
|
91
|
+
const input = await this.getInput(directory, inputPath)
|
|
92
|
+
|
|
93
|
+
tui.command(`java ${className} < ${inputPath} > ${outputPath}`)
|
|
94
|
+
|
|
95
|
+
const { exitCode } = await execa({
|
|
96
|
+
reject: false,
|
|
97
|
+
input,
|
|
98
|
+
stdout: { file: join(directory, outputPath) },
|
|
99
|
+
stderr: 'inherit',
|
|
100
|
+
cwd: directory,
|
|
101
|
+
})`java ${className}`
|
|
102
|
+
|
|
103
|
+
if (exitCode !== 0) throw new Error(`Execution failed for ${classPath}`)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { execa } from 'execa'
|
|
2
|
+
import { join } from 'path'
|
|
3
|
+
import tui from '../tui'
|
|
4
|
+
import type { Handler } from '../types'
|
|
5
|
+
import { readText, toolkitPrefix, writeText } from '../utils'
|
|
6
|
+
import { Compiler } from './base'
|
|
7
|
+
|
|
8
|
+
export class Python3_Compiler extends Compiler {
|
|
9
|
+
id(): string {
|
|
10
|
+
return 'Python3'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
name(): string {
|
|
14
|
+
return 'Python3'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type(): string {
|
|
18
|
+
return 'interpreter'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
language(): string {
|
|
22
|
+
return 'Python'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async version(): Promise<string> {
|
|
26
|
+
return await this.getVersion('python3 --version', 0)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
flags1(): string {
|
|
30
|
+
return ''
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
flags2(): string {
|
|
34
|
+
return ''
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
tool(): string {
|
|
38
|
+
return 'python3'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
extension(): string {
|
|
42
|
+
return 'py'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override async compileNormal(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
46
|
+
const source = await readText(join(directory, sourcePath))
|
|
47
|
+
|
|
48
|
+
tui.command(`tweak ${sourcePath} for turtle compatibility`)
|
|
49
|
+
const modSource = source
|
|
50
|
+
.replace('import turtle', 'import turtle_pil as turtle')
|
|
51
|
+
.replace('from turtle import', 'from turtle_pil import')
|
|
52
|
+
await writeText(join(directory, sourcePath), modSource)
|
|
53
|
+
|
|
54
|
+
tui.command(`python3 -m py_compile ${sourcePath}`)
|
|
55
|
+
const { exitCode } = await execa({
|
|
56
|
+
reject: false,
|
|
57
|
+
stderr: 'inherit',
|
|
58
|
+
stdout: 'inherit',
|
|
59
|
+
cwd: directory,
|
|
60
|
+
})`python3 -m py_compile ${sourcePath}`
|
|
61
|
+
|
|
62
|
+
if (exitCode !== 0) {
|
|
63
|
+
throw new Error(`Compilation failed for ${sourcePath}`)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return sourcePath
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
override async compileWithMain(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
70
|
+
tui.command(`add main.${this.extension()} to ${sourcePath}`)
|
|
71
|
+
await this.concatText(directory, [sourcePath, `main.${this.extension()}`], sourcePath)
|
|
72
|
+
|
|
73
|
+
tui.command(`python3 -m py_compile ${sourcePath}`)
|
|
74
|
+
const { exitCode } = await execa({
|
|
75
|
+
reject: false,
|
|
76
|
+
stderr: 'inherit',
|
|
77
|
+
stdout: 'inherit',
|
|
78
|
+
cwd: directory,
|
|
79
|
+
})`python3 -m py_compile ${sourcePath}`
|
|
80
|
+
|
|
81
|
+
if (exitCode !== 0) {
|
|
82
|
+
throw new Error(`Compilation failed for ${sourcePath}`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return sourcePath
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
override async execute(
|
|
89
|
+
handler: Handler,
|
|
90
|
+
directory: string,
|
|
91
|
+
sourcePath: string,
|
|
92
|
+
inputPath: string,
|
|
93
|
+
outputPath: string,
|
|
94
|
+
): Promise<void> {
|
|
95
|
+
const exePath = sourcePath
|
|
96
|
+
|
|
97
|
+
await this.rmInDir(directory, outputPath)
|
|
98
|
+
const input = await this.getInput(directory, inputPath)
|
|
99
|
+
|
|
100
|
+
tui.command(`python3 ${exePath} < ${inputPath} > ${outputPath}`)
|
|
101
|
+
|
|
102
|
+
const { exitCode } = await execa({
|
|
103
|
+
reject: false,
|
|
104
|
+
input,
|
|
105
|
+
stdout: { file: join(directory, outputPath) },
|
|
106
|
+
stderr: 'inherit',
|
|
107
|
+
cwd: directory,
|
|
108
|
+
})`python3 ${exePath}`
|
|
109
|
+
|
|
110
|
+
if (exitCode !== 0) throw new Error(`Execution failed for ${exePath}`)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { execa } from 'execa'
|
|
2
|
+
import { join, parse } from 'path'
|
|
3
|
+
import tui from '../tui'
|
|
4
|
+
import type { Handler } from '../types'
|
|
5
|
+
import { nothing, readText, toolkitPrefix, writeText } from '../utils'
|
|
6
|
+
import { Compiler } from './base'
|
|
7
|
+
|
|
8
|
+
export class RunClojure_Compiler extends Compiler {
|
|
9
|
+
id(): string {
|
|
10
|
+
return 'RunClojure'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
name(): string {
|
|
14
|
+
return 'RunClojure'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type(): string {
|
|
18
|
+
return 'interpreter'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
language(): string {
|
|
22
|
+
return 'Clojure'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async version(): Promise<string> {
|
|
26
|
+
return await this.getVersion('clj --version', 0)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
flags1(): string {
|
|
30
|
+
return ''
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
flags2(): string {
|
|
34
|
+
return ''
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
tool(): string {
|
|
38
|
+
return 'clj'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
extension(): string {
|
|
42
|
+
return 'clj'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override async compileNormal(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
46
|
+
await nothing()
|
|
47
|
+
|
|
48
|
+
tui.warning(`No compilation available for Clojure`)
|
|
49
|
+
|
|
50
|
+
return sourcePath
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override async compileWithMain(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
54
|
+
await nothing()
|
|
55
|
+
throw new Error('Method not implemented.')
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override async execute(
|
|
59
|
+
handler: Handler,
|
|
60
|
+
directory: string,
|
|
61
|
+
sourcePath: string,
|
|
62
|
+
inputPath: string,
|
|
63
|
+
outputPath: string,
|
|
64
|
+
): Promise<void> {
|
|
65
|
+
const newSourcePath = `${toolkitPrefix()}-${parse(sourcePath).name}-${parse(inputPath).name}.clj`
|
|
66
|
+
|
|
67
|
+
tui.command(`merge ${sourcePath} ${inputPath} > ${newSourcePath}`)
|
|
68
|
+
await this.mergeScripts(directory, sourcePath, inputPath, newSourcePath)
|
|
69
|
+
|
|
70
|
+
tui.command(`clj -M ${newSourcePath} > ${outputPath}`)
|
|
71
|
+
|
|
72
|
+
const { exitCode } = await execa({
|
|
73
|
+
reject: false,
|
|
74
|
+
stdout: { file: join(directory, outputPath) },
|
|
75
|
+
stderr: 'inherit',
|
|
76
|
+
cwd: directory,
|
|
77
|
+
})`clj -M ${newSourcePath}`
|
|
78
|
+
|
|
79
|
+
if (exitCode !== 0) throw new Error(`Execution failed for ${newSourcePath}`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async mergeScripts(
|
|
83
|
+
directory: string,
|
|
84
|
+
scriptPath1: string,
|
|
85
|
+
scriptPath2: string,
|
|
86
|
+
outputScriptPath: string,
|
|
87
|
+
): Promise<void> {
|
|
88
|
+
const script1 = await readText(join(directory, scriptPath1))
|
|
89
|
+
const script2 = await readText(join(directory, scriptPath2))
|
|
90
|
+
let mergedScript = script1
|
|
91
|
+
mergedScript += '\n\n\n'
|
|
92
|
+
for (const line of script2.split('\n')) {
|
|
93
|
+
if (line.trim() === '') {
|
|
94
|
+
mergedScript += '\n'
|
|
95
|
+
} else {
|
|
96
|
+
mergedScript += `(println ${line})\n`
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
await writeText(join(directory, outputScriptPath), mergedScript)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { execa } from 'execa'
|
|
2
|
+
import { join, parse } from 'path'
|
|
3
|
+
import tui from '../tui'
|
|
4
|
+
import type { Handler } from '../types'
|
|
5
|
+
import { nothing, readText, toolkitPrefix, writeText } from '../utils'
|
|
6
|
+
import { Compiler } from './base'
|
|
7
|
+
|
|
8
|
+
export class RunHaskell_Compiler extends Compiler {
|
|
9
|
+
id(): string {
|
|
10
|
+
return 'RunHaskell'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
name(): string {
|
|
14
|
+
return 'RunHaskell'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type(): string {
|
|
18
|
+
return 'interpreter'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
language(): string {
|
|
22
|
+
return 'Haskell'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async version(): Promise<string> {
|
|
26
|
+
return await this.getVersion('runhaskell --version', 0)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
flags1(): string {
|
|
30
|
+
return ''
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
flags2(): string {
|
|
34
|
+
return ''
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
tool(): string {
|
|
38
|
+
return 'ghc'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
extension(): string {
|
|
42
|
+
return 'hs'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override async compileNormal(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
46
|
+
// ghci -e ':q' solution.hs
|
|
47
|
+
// This will load and typecheck the file, then immediately quit.
|
|
48
|
+
// If there are compilation errors, they'll be shown. If it loads successfully and just exits, the code compiles.
|
|
49
|
+
// With execa, it seems we have to remove the quotes around :q
|
|
50
|
+
|
|
51
|
+
tui.command(`ghci -e ':q' ${sourcePath}`)
|
|
52
|
+
|
|
53
|
+
const { exitCode } = await execa({
|
|
54
|
+
reject: false,
|
|
55
|
+
stderr: 'inherit',
|
|
56
|
+
stdout: 'inherit',
|
|
57
|
+
cwd: directory,
|
|
58
|
+
})`ghci -e :q ${sourcePath}`
|
|
59
|
+
|
|
60
|
+
if (exitCode !== 0) {
|
|
61
|
+
throw new Error(`Compilation failed for ${sourcePath}`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return sourcePath
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
override async compileWithMain(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
68
|
+
await nothing()
|
|
69
|
+
throw new Error('Method not implemented.')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
override async execute(
|
|
73
|
+
handler: Handler,
|
|
74
|
+
directory: string,
|
|
75
|
+
sourcePath: string,
|
|
76
|
+
inputPath: string,
|
|
77
|
+
outputPath: string,
|
|
78
|
+
): Promise<void> {
|
|
79
|
+
const newSourcePath = `${toolkitPrefix()}-${parse(sourcePath).name}-${parse(inputPath).name}.hs`
|
|
80
|
+
|
|
81
|
+
tui.command(`merge ${sourcePath} ${inputPath} > ${newSourcePath}`)
|
|
82
|
+
await this.mergeScripts(directory, sourcePath, inputPath, newSourcePath)
|
|
83
|
+
|
|
84
|
+
tui.command(`runhaskell ${newSourcePath} > ${outputPath}`)
|
|
85
|
+
|
|
86
|
+
const { exitCode } = await execa({
|
|
87
|
+
reject: false,
|
|
88
|
+
stdout: { file: join(directory, outputPath) },
|
|
89
|
+
stderr: 'inherit',
|
|
90
|
+
cwd: directory,
|
|
91
|
+
})`runhaskell ${newSourcePath}`
|
|
92
|
+
|
|
93
|
+
if (exitCode !== 0) throw new Error(`Execution failed for ${newSourcePath}`)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async mergeScripts(
|
|
97
|
+
directory: string,
|
|
98
|
+
scriptPath1: string,
|
|
99
|
+
scriptPath2: string,
|
|
100
|
+
outputScriptPath: string,
|
|
101
|
+
): Promise<void> {
|
|
102
|
+
const script1 = await readText(join(directory, scriptPath1))
|
|
103
|
+
const script2 = await readText(join(directory, scriptPath2))
|
|
104
|
+
let mergedScript = script1
|
|
105
|
+
mergedScript += '\n\n\nmain = do\n'
|
|
106
|
+
for (const line of script2.split('\n')) {
|
|
107
|
+
if (line.trim() === '') {
|
|
108
|
+
mergedScript += '\n'
|
|
109
|
+
} else if (line.startsWith('let')) {
|
|
110
|
+
mergedScript += ` ${line}\n`
|
|
111
|
+
} else {
|
|
112
|
+
mergedScript += ` print $ ${line}\n`
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
await writeText(join(directory, outputScriptPath), mergedScript)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { execa } from 'execa'
|
|
2
|
+
import { cp } from 'fs/promises'
|
|
3
|
+
import { join, parse } from 'path'
|
|
4
|
+
import tui from '../tui'
|
|
5
|
+
import type { Handler } from '../types'
|
|
6
|
+
import { nothing, readText, toolkitPrefix, writeText } from '../utils'
|
|
7
|
+
import { Compiler } from './base'
|
|
8
|
+
|
|
9
|
+
export class RunPython_Compiler extends Compiler {
|
|
10
|
+
id(): string {
|
|
11
|
+
return 'RunPython'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
name(): string {
|
|
15
|
+
return 'RunPython'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
type(): string {
|
|
19
|
+
return 'interpreter'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
language(): string {
|
|
23
|
+
return 'Python'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async version(): Promise<string> {
|
|
27
|
+
return await this.getVersion('python3 --version', 0)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
flags1(): string {
|
|
31
|
+
return ''
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
flags2(): string {
|
|
35
|
+
return ''
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
tool(): string {
|
|
39
|
+
return 'python3'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
extension(): string {
|
|
43
|
+
return 'py'
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
override async compileNormal(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
47
|
+
tui.command(`python3 -m py_compile ${sourcePath}`)
|
|
48
|
+
|
|
49
|
+
const { exitCode } = await execa({
|
|
50
|
+
reject: false,
|
|
51
|
+
stderr: 'inherit',
|
|
52
|
+
stdout: 'inherit',
|
|
53
|
+
cwd: directory,
|
|
54
|
+
})`python3 -m py_compile ${sourcePath}`
|
|
55
|
+
|
|
56
|
+
if (exitCode !== 0) {
|
|
57
|
+
throw new Error(`Compilation failed for ${sourcePath}`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return sourcePath
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
override async compileWithMain(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
64
|
+
await nothing()
|
|
65
|
+
throw new Error('Method not implemented.')
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
override async execute(
|
|
69
|
+
handler: Handler,
|
|
70
|
+
directory: string,
|
|
71
|
+
sourcePath: string,
|
|
72
|
+
inputPath: string,
|
|
73
|
+
outputPath: string,
|
|
74
|
+
): Promise<void> {
|
|
75
|
+
const newSourcePath = `${toolkitPrefix()}-${parse(sourcePath).name}-${parse(inputPath).name}.py`
|
|
76
|
+
|
|
77
|
+
tui.command(`merge ${sourcePath} ${inputPath} > ${newSourcePath}`)
|
|
78
|
+
await this.mergeScripts(directory, sourcePath, inputPath, newSourcePath)
|
|
79
|
+
|
|
80
|
+
tui.command(`python3 ${newSourcePath} > ${outputPath}`)
|
|
81
|
+
|
|
82
|
+
const { exitCode } = await execa({
|
|
83
|
+
reject: false,
|
|
84
|
+
stdout: { file: join(directory, outputPath) },
|
|
85
|
+
stderr: 'inherit',
|
|
86
|
+
cwd: directory,
|
|
87
|
+
})`python3 ${newSourcePath}`
|
|
88
|
+
|
|
89
|
+
if (exitCode !== 0) throw new Error(`Execution failed for ${newSourcePath}`)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async mergeScripts(
|
|
93
|
+
directory: string,
|
|
94
|
+
scriptPath1: string,
|
|
95
|
+
scriptPath2: string,
|
|
96
|
+
outputScriptPath: string,
|
|
97
|
+
): Promise<void> {
|
|
98
|
+
const script1 = await readText(join(directory, scriptPath1))
|
|
99
|
+
const script2 = await readText(join(directory, scriptPath2))
|
|
100
|
+
const mergedScript = script1 + '\n\n\n' + script2
|
|
101
|
+
await writeText(join(directory, outputScriptPath), mergedScript)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Compiler } from './base'
|
|
2
|
+
|
|
3
|
+
export class Rust_Compiler extends Compiler {
|
|
4
|
+
id(): string {
|
|
5
|
+
return 'Rust'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
name(): string {
|
|
9
|
+
return 'Rust Compiler'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type(): string {
|
|
13
|
+
return 'compiler'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
language(): string {
|
|
17
|
+
return 'Rust'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async version(): Promise<string> {
|
|
21
|
+
return await this.getVersion('rustc --version', 0)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
flags1(): string {
|
|
25
|
+
return '-C opt-level=2 -D warnings'
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
flags2(): string {
|
|
29
|
+
return '-C opt-level=2 -D warnings'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
tool(): string {
|
|
33
|
+
return 'rustc'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
extension(): string {
|
|
37
|
+
return 'rs'
|
|
38
|
+
}
|
|
39
|
+
}
|