@jpetit/toolkit 3.0.23 → 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/assets/prompts/creators/create-solution.tpl.txt +10 -0
- package/assets/prompts/creators/create-statement.tpl.txt +21 -0
- package/assets/prompts/creators/create-translation.tpl.txt +5 -0
- package/assets/prompts/creators/private-test-cases.txt +6 -0
- package/assets/prompts/creators/sample-test-cases.txt +6 -0
- package/assets/prompts/creators/system-prompt.txt +2 -0
- package/assets/prompts/examples/statement-coda.tex +7 -0
- package/assets/prompts/examples/statement.tex +19 -0
- package/assets/prompts/generators/efficiency.md +41 -0
- package/assets/prompts/generators/hard.md +47 -0
- package/assets/prompts/generators/random.md +39 -0
- package/assets/prompts/proglangs/cc.md +3 -0
- package/assets/prompts/proglangs/py.md +40 -0
- package/lib/ai.ts +60 -4
- package/lib/cleaner.ts +24 -13
- package/lib/compilers/base.ts +70 -14
- package/lib/compilers/clojure.ts +21 -10
- package/lib/compilers/gcc.ts +4 -33
- package/lib/compilers/ghc.ts +4 -40
- package/lib/compilers/gxx.ts +4 -33
- package/lib/compilers/index.ts +9 -0
- package/lib/compilers/java.ts +105 -0
- package/lib/compilers/python3.ts +44 -37
- package/lib/compilers/run-clojure.ts +101 -0
- package/lib/compilers/run-haskell.ts +26 -22
- package/lib/compilers/run-python.ts +29 -35
- 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 +6 -0
- package/lib/doctor.ts +86 -6
- package/lib/generate.ts +132 -290
- package/lib/helpers.ts +48 -0
- package/lib/inspector.ts +253 -0
- package/lib/jutge_api_client.ts +4631 -0
- package/lib/maker.ts +202 -289
- package/lib/settings.ts +26 -17
- package/lib/tui.ts +25 -15
- package/lib/types.ts +40 -5
- package/lib/upload.ts +216 -0
- package/lib/utils.ts +82 -14
- package/lib/versions.ts +46 -0
- package/package.json +50 -11
- package/toolkit/about.ts +43 -0
- package/toolkit/ai.ts +44 -18
- package/toolkit/check.ts +16 -0
- package/toolkit/clean.ts +16 -26
- package/toolkit/compilers.ts +4 -4
- package/toolkit/config.ts +91 -0
- package/toolkit/create.ts +30 -58
- package/toolkit/doctor.ts +15 -11
- package/toolkit/generate.ts +195 -98
- package/toolkit/index.ts +32 -21
- package/toolkit/make.ts +12 -48
- package/toolkit/upgrade.ts +9 -0
- package/toolkit/upload.ts +19 -0
- package/toolkit/create-jutge-ai.ts +0 -101
- package/toolkit/create-template.ts +0 -55
- package/toolkit/create-wizard.ts +0 -6
- package/toolkit/init.ts +0 -56
- package/toolkit/verify.ts +0 -19
package/lib/compilers/gcc.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
import { type Handler } from '../types'
|
|
2
|
-
import tui from '../tui'
|
|
3
1
|
import { Compiler } from './base'
|
|
4
|
-
import { rm, exists } from 'fs/promises'
|
|
5
|
-
import { join } from 'path'
|
|
6
|
-
import { execa } from 'execa'
|
|
7
2
|
|
|
8
3
|
export class GCC_Compiler extends Compiler {
|
|
9
4
|
id(): string {
|
|
@@ -34,35 +29,11 @@ export class GCC_Compiler extends Compiler {
|
|
|
34
29
|
return ''
|
|
35
30
|
}
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
return '
|
|
32
|
+
tool(): string {
|
|
33
|
+
return 'gcc'
|
|
39
34
|
}
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const fullExePath = join(directory, exePath)
|
|
44
|
-
await rm(fullExePath, { force: true })
|
|
45
|
-
|
|
46
|
-
if (handler.source_modifier === 'none') {
|
|
47
|
-
tui.command(`gcc ${this.flags1()} ${sourcePath} -o ${exePath}`)
|
|
48
|
-
await execa({
|
|
49
|
-
reject: false,
|
|
50
|
-
stderr: 'inherit',
|
|
51
|
-
stdout: 'inherit',
|
|
52
|
-
cwd: directory,
|
|
53
|
-
})`gcc ${this.flags1().split(' ')} ${sourcePath} -o ${exePath}`
|
|
54
|
-
} else if (handler.source_modifier === 'no_main') {
|
|
55
|
-
tui.command(`gcc ${this.flags1()} ${sourcePath} main.c -o ${exePath}`)
|
|
56
|
-
await execa({
|
|
57
|
-
reject: false,
|
|
58
|
-
stderr: 'inherit',
|
|
59
|
-
stdout: 'inherit',
|
|
60
|
-
cwd: directory,
|
|
61
|
-
})`gcc ${this.flags1().split(' ')} ${sourcePath} main.c -o ${exePath}`
|
|
62
|
-
} else {
|
|
63
|
-
throw new Error(`Unknown source modifier: ${handler.source_modifier}`)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!(await exists(fullExePath))) throw new Error(`Compilation failed for ${sourcePath}`)
|
|
36
|
+
extension(): string {
|
|
37
|
+
return 'c'
|
|
67
38
|
}
|
|
68
39
|
}
|
package/lib/compilers/ghc.ts
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
import { execa } from 'execa'
|
|
2
|
-
import { exists, rm } from 'fs/promises'
|
|
3
|
-
import { concatText } from '../utils'
|
|
4
|
-
import { join } from 'path'
|
|
5
|
-
import tui from '../tui'
|
|
6
|
-
import { type Handler } from '../types'
|
|
7
1
|
import { Compiler } from './base'
|
|
8
2
|
|
|
9
3
|
export class GHC_Compiler extends Compiler {
|
|
@@ -35,41 +29,11 @@ export class GHC_Compiler extends Compiler {
|
|
|
35
29
|
return '-O3'
|
|
36
30
|
}
|
|
37
31
|
|
|
38
|
-
|
|
39
|
-
return '
|
|
32
|
+
tool(): string {
|
|
33
|
+
return 'ghc'
|
|
40
34
|
}
|
|
41
35
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const fullOutputPath = join(directory, outputPath)
|
|
45
|
-
await rm(fullOutputPath, { force: true })
|
|
46
|
-
|
|
47
|
-
if (handler.source_modifier === 'none') {
|
|
48
|
-
tui.command(`ghc ${this.flags1()} ${sourcePath} -o ${outputPath}`)
|
|
49
|
-
await execa({
|
|
50
|
-
reject: false,
|
|
51
|
-
stderr: 'inherit',
|
|
52
|
-
stdout: 'inherit',
|
|
53
|
-
cwd: directory,
|
|
54
|
-
})`ghc ${this.flags1().split(' ')} ${sourcePath} -o ${outputPath}`
|
|
55
|
-
} else if (handler.source_modifier === 'no_main') {
|
|
56
|
-
const wrapperPath = `wrapper-${sourcePath}`
|
|
57
|
-
|
|
58
|
-
tui.command(`concat ${sourcePath} and main.hs into ${wrapperPath}`, { italic: true })
|
|
59
|
-
await concatText([join(directory, sourcePath), join(directory, 'main.hs')], join(directory, wrapperPath))
|
|
60
|
-
|
|
61
|
-
tui.command(`ghc ${this.flags1()} ${wrapperPath} -o ${outputPath}`)
|
|
62
|
-
|
|
63
|
-
await execa({
|
|
64
|
-
reject: false,
|
|
65
|
-
stderr: 'inherit',
|
|
66
|
-
stdout: 'inherit',
|
|
67
|
-
cwd: directory,
|
|
68
|
-
})`ghc ${this.flags1().split(' ')} ${wrapperPath} -o ${outputPath}`
|
|
69
|
-
} else {
|
|
70
|
-
throw new Error(`Unknown source modifier: ${handler.source_modifier}`)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (!(await exists(fullOutputPath))) throw new Error(`Compilation failed for ${sourcePath}`)
|
|
36
|
+
extension(): string {
|
|
37
|
+
return 'hs'
|
|
74
38
|
}
|
|
75
39
|
}
|
package/lib/compilers/gxx.ts
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
import { execa } from 'execa'
|
|
2
|
-
import { exists, rm } from 'fs/promises'
|
|
3
|
-
import { join } from 'path'
|
|
4
|
-
import tui from '../tui'
|
|
5
|
-
import { type Handler } from '../types'
|
|
6
1
|
import { Compiler } from './base'
|
|
7
2
|
|
|
8
3
|
export class GXX_Compiler extends Compiler {
|
|
@@ -34,35 +29,11 @@ export class GXX_Compiler extends Compiler {
|
|
|
34
29
|
return '-std=c++17 -D_JUDGE_ -O2 -DNDEBUG -Wall -Wextra -Wno-sign-compare -Wshadow'
|
|
35
30
|
}
|
|
36
31
|
|
|
37
|
-
|
|
38
|
-
return '
|
|
32
|
+
tool(): string {
|
|
33
|
+
return 'g++'
|
|
39
34
|
}
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const fullOutputPath = join(directory, outputPath)
|
|
44
|
-
await rm(fullOutputPath, { force: true })
|
|
45
|
-
|
|
46
|
-
if (handler.source_modifier === 'none') {
|
|
47
|
-
tui.command(`g++ ${this.flags1()} ${sourcePath} -o ${outputPath}`)
|
|
48
|
-
await execa({
|
|
49
|
-
reject: false,
|
|
50
|
-
stderr: 'inherit',
|
|
51
|
-
stdout: 'inherit',
|
|
52
|
-
cwd: directory,
|
|
53
|
-
})`g++ ${this.flags1().split(' ')} ${sourcePath} -o ${outputPath}`
|
|
54
|
-
} else if (handler.source_modifier === 'no_main') {
|
|
55
|
-
tui.command(`g++ ${this.flags1()} ${sourcePath} main.cc -o ${outputPath}`)
|
|
56
|
-
await execa({
|
|
57
|
-
reject: false,
|
|
58
|
-
stderr: 'inherit',
|
|
59
|
-
stdout: 'inherit',
|
|
60
|
-
cwd: directory,
|
|
61
|
-
})`g++ ${this.flags1().split(' ')} ${sourcePath} main.cc -o ${outputPath}`
|
|
62
|
-
} else {
|
|
63
|
-
throw new Error(`Unknown source modifier: ${handler.source_modifier}`)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (!(await exists(fullOutputPath))) throw new Error(`Compilation failed for ${sourcePath}`)
|
|
36
|
+
extension(): string {
|
|
37
|
+
return 'cc'
|
|
67
38
|
}
|
|
68
39
|
}
|
package/lib/compilers/index.ts
CHANGED
|
@@ -5,8 +5,11 @@ import { GXX_Compiler } from './gxx'
|
|
|
5
5
|
import { Python3_Compiler } from './python3'
|
|
6
6
|
import { GHC_Compiler } from './ghc'
|
|
7
7
|
import { Clojure_Compiler } from './clojure'
|
|
8
|
+
import { Java_Compiler } from './java'
|
|
9
|
+
import { Rust_Compiler } from './rust'
|
|
8
10
|
import { RunPython_Compiler } from './run-python'
|
|
9
11
|
import { RunHaskell_Compiler } from './run-haskell'
|
|
12
|
+
import { RunClojure_Compiler } from './run-clojure'
|
|
10
13
|
|
|
11
14
|
const compilersRegistryById: Record<string, new () => Compiler> = {
|
|
12
15
|
C: GCC_Compiler,
|
|
@@ -14,8 +17,12 @@ const compilersRegistryById: Record<string, new () => Compiler> = {
|
|
|
14
17
|
Python3: Python3_Compiler,
|
|
15
18
|
Haskell: GHC_Compiler,
|
|
16
19
|
Clojure: Clojure_Compiler,
|
|
20
|
+
Java: Java_Compiler,
|
|
21
|
+
Rust: Rust_Compiler,
|
|
22
|
+
|
|
17
23
|
RunPython: RunPython_Compiler,
|
|
18
24
|
RunHaskell: RunHaskell_Compiler,
|
|
25
|
+
RunClojure: RunClojure_Compiler,
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
const compilersRegistryByExtension: Record<string, new () => Compiler> = {
|
|
@@ -24,6 +31,8 @@ const compilersRegistryByExtension: Record<string, new () => Compiler> = {
|
|
|
24
31
|
py: Python3_Compiler,
|
|
25
32
|
hs: GHC_Compiler,
|
|
26
33
|
clj: Clojure_Compiler,
|
|
34
|
+
java: Java_Compiler,
|
|
35
|
+
rs: Rust_Compiler,
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
export function getCompilerById(id: string): Compiler {
|
|
@@ -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
|
+
}
|
package/lib/compilers/python3.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { execa } from 'execa'
|
|
2
|
-
import { exists, rm } from 'fs/promises'
|
|
3
2
|
import { join } from 'path'
|
|
4
3
|
import tui from '../tui'
|
|
5
4
|
import type { Handler } from '../types'
|
|
6
|
-
import { readText, writeText } from '../utils'
|
|
5
|
+
import { readText, toolkitPrefix, writeText } from '../utils'
|
|
7
6
|
import { Compiler } from './base'
|
|
8
7
|
|
|
9
8
|
export class Python3_Compiler extends Compiler {
|
|
@@ -35,40 +34,55 @@ export class Python3_Compiler extends Compiler {
|
|
|
35
34
|
return ''
|
|
36
35
|
}
|
|
37
36
|
|
|
37
|
+
tool(): string {
|
|
38
|
+
return 'python3'
|
|
39
|
+
}
|
|
40
|
+
|
|
38
41
|
extension(): string {
|
|
39
42
|
return 'py'
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
async
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
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}`)
|
|
59
64
|
}
|
|
60
|
-
await writeText(fullWrapperPath, wrapperSource)
|
|
61
65
|
|
|
62
|
-
|
|
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)
|
|
63
72
|
|
|
73
|
+
tui.command(`python3 -m py_compile ${sourcePath}`)
|
|
64
74
|
const { exitCode } = await execa({
|
|
65
75
|
reject: false,
|
|
66
76
|
stderr: 'inherit',
|
|
67
77
|
stdout: 'inherit',
|
|
68
78
|
cwd: directory,
|
|
69
|
-
})`python3 -m py_compile ${
|
|
79
|
+
})`python3 -m py_compile ${sourcePath}`
|
|
70
80
|
|
|
71
|
-
if (exitCode !== 0)
|
|
81
|
+
if (exitCode !== 0) {
|
|
82
|
+
throw new Error(`Compilation failed for ${sourcePath}`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return sourcePath
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
override async execute(
|
|
@@ -78,28 +92,21 @@ export class Python3_Compiler extends Compiler {
|
|
|
78
92
|
inputPath: string,
|
|
79
93
|
outputPath: string,
|
|
80
94
|
): Promise<void> {
|
|
81
|
-
const
|
|
82
|
-
const fullWrapperPath = join(directory, wrapperPath)
|
|
83
|
-
|
|
84
|
-
if (!(await exists(join(directory, wrapperPath)))) {
|
|
85
|
-
throw new Error(`Executable file ${wrapperPath} does not exist in directory ${directory}`)
|
|
86
|
-
}
|
|
95
|
+
const exePath = sourcePath
|
|
87
96
|
|
|
88
|
-
|
|
89
|
-
const
|
|
90
|
-
await rm(fullOutputPath, { force: true })
|
|
91
|
-
const input = await readText(fullInputPath)
|
|
97
|
+
await this.rmInDir(directory, outputPath)
|
|
98
|
+
const input = await this.getInput(directory, inputPath)
|
|
92
99
|
|
|
93
|
-
tui.command(`python3 ${
|
|
100
|
+
tui.command(`python3 ${exePath} < ${inputPath} > ${outputPath}`)
|
|
94
101
|
|
|
95
102
|
const { exitCode } = await execa({
|
|
96
103
|
reject: false,
|
|
97
104
|
input,
|
|
98
|
-
stdout: { file:
|
|
105
|
+
stdout: { file: join(directory, outputPath) },
|
|
99
106
|
stderr: 'inherit',
|
|
100
107
|
cwd: directory,
|
|
101
|
-
})`python3 ${
|
|
108
|
+
})`python3 ${exePath}`
|
|
102
109
|
|
|
103
|
-
if (exitCode !== 0) throw new Error(`Execution failed for ${
|
|
110
|
+
if (exitCode !== 0) throw new Error(`Execution failed for ${exePath}`)
|
|
104
111
|
}
|
|
105
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
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { execa } from 'execa'
|
|
2
|
-
import {
|
|
3
|
-
import { join } from 'path'
|
|
2
|
+
import { join, parse } from 'path'
|
|
4
3
|
import tui from '../tui'
|
|
5
4
|
import type { Handler } from '../types'
|
|
6
|
-
import { readText, writeText } from '../utils'
|
|
5
|
+
import { nothing, readText, toolkitPrefix, writeText } from '../utils'
|
|
7
6
|
import { Compiler } from './base'
|
|
8
7
|
|
|
9
8
|
export class RunHaskell_Compiler extends Compiler {
|
|
@@ -16,7 +15,7 @@ export class RunHaskell_Compiler extends Compiler {
|
|
|
16
15
|
}
|
|
17
16
|
|
|
18
17
|
type(): string {
|
|
19
|
-
return '
|
|
18
|
+
return 'interpreter'
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
language(): string {
|
|
@@ -24,7 +23,7 @@ export class RunHaskell_Compiler extends Compiler {
|
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
async version(): Promise<string> {
|
|
27
|
-
return await this.getVersion('
|
|
26
|
+
return await this.getVersion('runhaskell --version', 0)
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
flags1(): string {
|
|
@@ -35,15 +34,15 @@ export class RunHaskell_Compiler extends Compiler {
|
|
|
35
34
|
return ''
|
|
36
35
|
}
|
|
37
36
|
|
|
37
|
+
tool(): string {
|
|
38
|
+
return 'ghc'
|
|
39
|
+
}
|
|
40
|
+
|
|
38
41
|
extension(): string {
|
|
39
42
|
return 'hs'
|
|
40
43
|
}
|
|
41
44
|
|
|
42
|
-
async
|
|
43
|
-
if (handler.source_modifier !== 'none') {
|
|
44
|
-
throw new Error(`Unknown source modifier: ${handler.source_modifier as string}`)
|
|
45
|
-
}
|
|
46
|
-
|
|
45
|
+
override async compileNormal(handler: Handler, directory: string, sourcePath: string): Promise<string> {
|
|
47
46
|
// ghci -e ':q' solution.hs
|
|
48
47
|
// This will load and typecheck the file, then immediately quit.
|
|
49
48
|
// If there are compilation errors, they'll be shown. If it loads successfully and just exits, the code compiles.
|
|
@@ -58,7 +57,16 @@ export class RunHaskell_Compiler extends Compiler {
|
|
|
58
57
|
cwd: directory,
|
|
59
58
|
})`ghci -e :q ${sourcePath}`
|
|
60
59
|
|
|
61
|
-
if (exitCode !== 0)
|
|
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.')
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
override async execute(
|
|
@@ -68,25 +76,21 @@ export class RunHaskell_Compiler extends Compiler {
|
|
|
68
76
|
inputPath: string,
|
|
69
77
|
outputPath: string,
|
|
70
78
|
): Promise<void> {
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
tui.command(`Merging solution.hs and ${inputPath} into ${mergedPath}`, { italic: true })
|
|
74
|
-
await this.mergeScripts(directory, 'solution.hs', inputPath, mergedPath)
|
|
75
|
-
|
|
76
|
-
const fullOutputPath = join(directory, outputPath)
|
|
79
|
+
const newSourcePath = `${toolkitPrefix()}-${parse(sourcePath).name}-${parse(inputPath).name}.hs`
|
|
77
80
|
|
|
78
|
-
|
|
81
|
+
tui.command(`merge ${sourcePath} ${inputPath} > ${newSourcePath}`)
|
|
82
|
+
await this.mergeScripts(directory, sourcePath, inputPath, newSourcePath)
|
|
79
83
|
|
|
80
|
-
tui.command(`runhaskell ${
|
|
84
|
+
tui.command(`runhaskell ${newSourcePath} > ${outputPath}`)
|
|
81
85
|
|
|
82
86
|
const { exitCode } = await execa({
|
|
83
87
|
reject: false,
|
|
84
|
-
stdout: { file:
|
|
88
|
+
stdout: { file: join(directory, outputPath) },
|
|
85
89
|
stderr: 'inherit',
|
|
86
90
|
cwd: directory,
|
|
87
|
-
})`runhaskell ${
|
|
91
|
+
})`runhaskell ${newSourcePath}`
|
|
88
92
|
|
|
89
|
-
if (exitCode !== 0) throw new Error(`Execution failed for ${
|
|
93
|
+
if (exitCode !== 0) throw new Error(`Execution failed for ${newSourcePath}`)
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
async mergeScripts(
|