@jpetit/toolkit 3.0.4 → 3.0.6
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/package.json +11 -6
- package/toolkit/index.ts +18 -1
- package/.prettierignore +0 -11
- package/.prettierrc.json +0 -9
- package/.vscode/settings.json +0 -26
- package/assets.zip +0 -0
- package/eslint.config.mjs +0 -31
- package/lib/ai.ts +0 -138
- package/lib/assets.ts +0 -31
- package/lib/cleaner.ts +0 -58
- package/lib/compilers/_frompython.ts +0 -388
- package/lib/compilers/base.ts +0 -97
- package/lib/compilers/gcc.ts +0 -47
- package/lib/compilers/gxx.ts +0 -47
- package/lib/compilers/index.ts +0 -61
- package/lib/compilers/python3.ts +0 -67
- package/lib/data.ts +0 -19
- package/lib/doctor.ts +0 -104
- package/lib/generate.ts +0 -333
- package/lib/maker.ts +0 -535
- package/lib/settings.ts +0 -42
- package/lib/tui.ts +0 -69
- package/lib/utils.ts +0 -83
- package/problems/maxim2.pbm/Main.java +0 -13
- package/problems/maxim2.pbm/distillation.yml +0 -7
- package/problems/maxim2.pbm/distilled-01.inp +0 -1
- package/problems/maxim2.pbm/distilled-02.inp +0 -1
- package/problems/maxim2.pbm/distilled-03.inp +0 -1
- package/problems/maxim2.pbm/distiller.yml +0 -2
- package/problems/maxim2.pbm/generate-inputs.py +0 -9
- package/problems/maxim2.pbm/handler.yml +0 -2
- package/problems/maxim2.pbm/ma-1.inp +0 -1
- package/problems/maxim2.pbm/ma-2.inp +0 -1
- package/problems/maxim2.pbm/ma-3.inp +0 -1
- package/problems/maxim2.pbm/ma-4.inp +0 -1
- package/problems/maxim2.pbm/ma-5.inp +0 -1
- package/problems/maxim2.pbm/per-doubles.inp +0 -1
- package/problems/maxim2.pbm/problem.ca.html +0 -11
- package/problems/maxim2.pbm/problem.ca.md +0 -19
- package/problems/maxim2.pbm/problem.ca.tex +0 -17
- package/problems/maxim2.pbm/problem.ca.txt +0 -19
- package/problems/maxim2.pbm/problem.ca.yml +0 -3
- package/problems/maxim2.pbm/problem.en.html +0 -11
- package/problems/maxim2.pbm/problem.en.md +0 -19
- package/problems/maxim2.pbm/problem.en.tex +0 -16
- package/problems/maxim2.pbm/problem.en.txt +0 -19
- package/problems/maxim2.pbm/problem.en.yml +0 -4
- package/problems/maxim2.pbm/sample-1.inp +0 -1
- package/problems/maxim2.pbm/sample-2.inp +0 -1
- package/problems/maxim2.pbm/sample-3.inp +0 -1
- package/problems/maxim2.pbm/solution.c +0 -12
- package/problems/maxim2.pbm/solution.cc +0 -13
- package/problems/maxim2.pbm/solution.java +0 -13
- package/problems/maxim2.pbm/solution.pas +0 -9
- package/problems/maxim2.pbm/solution.py +0 -5
- package/problems/maxim2.pbm/tags.yml +0 -2
- package/problems/maxim2.pbm/test_-1_-1.inp +0 -1
- package/problems/maxim2.pbm/test_-1_-2.inp +0 -1
- package/problems/maxim2.pbm/test_-1_0.inp +0 -1
- package/problems/maxim2.pbm/test_-1_1.inp +0 -1
- package/problems/maxim2.pbm/test_-2_-1.inp +0 -1
- package/problems/maxim2.pbm/test_-2_-2.inp +0 -1
- package/problems/maxim2.pbm/test_-2_0.inp +0 -1
- package/problems/maxim2.pbm/test_-2_1.inp +0 -1
- package/problems/maxim2.pbm/test_0_-1.inp +0 -1
- package/problems/maxim2.pbm/test_0_-2.inp +0 -1
- package/problems/maxim2.pbm/test_0_0.inp +0 -1
- package/problems/maxim2.pbm/test_0_1.inp +0 -1
- package/problems/maxim2.pbm/test_1_-1.inp +0 -1
- package/problems/maxim2.pbm/test_1_-2.inp +0 -1
- package/problems/maxim2.pbm/test_1_0.inp +0 -1
- package/problems/maxim2.pbm/test_1_1.inp +0 -1
- package/test.ts +0 -3
- package/toolkit/ai.ts +0 -30
- package/toolkit/clean.ts +0 -19
- package/toolkit/compilers.ts +0 -29
- package/toolkit/create-jutge-ai.ts +0 -101
- package/toolkit/create-template.ts +0 -51
- package/toolkit/create-wizard.ts +0 -4
- package/toolkit/create.ts +0 -75
- package/toolkit/doctor.ts +0 -17
- package/toolkit/init.ts +0 -66
- package/toolkit/make.ts +0 -60
- package/toolkit/verify.ts +0 -19
- package/tsconfig.json +0 -38
- package/types/zip.d.ts +0 -4
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
import { $ } from 'bun'
|
|
2
|
-
import chalk from 'chalk'
|
|
3
|
-
import { access, copyFile, mkdir, readFile, rename, rm, unlink, writeFile } from 'fs/promises'
|
|
4
|
-
|
|
5
|
-
// Constants
|
|
6
|
-
const MAX_COMPILATION_TIME = 30000 // 30 seconds in milliseconds
|
|
7
|
-
|
|
8
|
-
// Custom Errors
|
|
9
|
-
export class CompilationTooLongError extends Error {
|
|
10
|
-
constructor() {
|
|
11
|
-
super('Compilation time exceeded')
|
|
12
|
-
this.name = 'CompilationTooLongError'
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export class ExecutionError extends Error {
|
|
17
|
-
constructor(message: string) {
|
|
18
|
-
super(message)
|
|
19
|
-
this.name = 'ExecutionError'
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class CompilationError extends Error {
|
|
24
|
-
constructor(message: string) {
|
|
25
|
-
super(message)
|
|
26
|
-
this.name = 'CompilationError'
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface CompilerInfo {
|
|
31
|
-
compiler_id: string
|
|
32
|
-
name: string
|
|
33
|
-
language: string
|
|
34
|
-
version: string
|
|
35
|
-
flags1: string
|
|
36
|
-
flags2: string
|
|
37
|
-
extension: string
|
|
38
|
-
type: string
|
|
39
|
-
warning: string
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
interface Handler {
|
|
43
|
-
source_modifier?: string
|
|
44
|
-
[key: string]: any
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const compilersList: Record<string, typeof Compiler> = {}
|
|
48
|
-
|
|
49
|
-
function compiler(baseClass: typeof Compiler) {
|
|
50
|
-
return function <T extends typeof Compiler>(derivedClass: T) {
|
|
51
|
-
compilersList[derivedClass.name] = derivedClass
|
|
52
|
-
return derivedClass
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export abstract class Compiler {
|
|
57
|
-
protected handler: Handler
|
|
58
|
-
protected _name: string
|
|
59
|
-
static availableCompilers: string[] = []
|
|
60
|
-
|
|
61
|
-
constructor(handler: Handler | null, name: string | null) {
|
|
62
|
-
this.handler = handler || {}
|
|
63
|
-
this._name = name || ''
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
abstract name(): string
|
|
67
|
-
abstract type(): string
|
|
68
|
-
abstract executable(): string
|
|
69
|
-
abstract language(): string
|
|
70
|
-
abstract version(): Promise<string>
|
|
71
|
-
abstract flags1(): string
|
|
72
|
-
abstract flags2(): string
|
|
73
|
-
abstract extension(): string
|
|
74
|
-
abstract compile(): Promise<boolean>
|
|
75
|
-
abstract execute(tst: string, correct: boolean, iterations?: number): Promise<number>
|
|
76
|
-
|
|
77
|
-
id(): string {
|
|
78
|
-
return this.constructor.name.replace('Compiler_', '').replace('XX', '++')
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
warning(): string {
|
|
82
|
-
return ''
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async prepareExecution(ori: string): Promise<void> {
|
|
86
|
-
// Override in subclasses if needed
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
protected async executeCompiler(cmd: string): Promise<void> {
|
|
90
|
-
console.log(chalk.dim(cmd))
|
|
91
|
-
|
|
92
|
-
return new Promise((resolve, reject) => {
|
|
93
|
-
const startTime = Date.now()
|
|
94
|
-
const proc = Bun.spawn(cmd.split(' '), {
|
|
95
|
-
stdout: 'pipe',
|
|
96
|
-
stderr: 'pipe',
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
let output = ''
|
|
100
|
-
let hasError = false
|
|
101
|
-
|
|
102
|
-
const timeout = setTimeout(() => {
|
|
103
|
-
proc.kill()
|
|
104
|
-
console.log(chalk.bold.red('Compilation time exceeded!'))
|
|
105
|
-
reject(new CompilationTooLongError())
|
|
106
|
-
}, MAX_COMPILATION_TIME)
|
|
107
|
-
|
|
108
|
-
;(async () => {
|
|
109
|
-
try {
|
|
110
|
-
const [stdout, stderr] = await Promise.all([
|
|
111
|
-
new Response(proc.stdout).text(),
|
|
112
|
-
new Response(proc.stderr).text(),
|
|
113
|
-
])
|
|
114
|
-
|
|
115
|
-
output = stdout + stderr
|
|
116
|
-
if (stderr.length > 0) {
|
|
117
|
-
hasError = true
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const exitCode = await proc.exited
|
|
121
|
-
clearTimeout(timeout)
|
|
122
|
-
|
|
123
|
-
if (exitCode !== 0 || hasError || output.length > 0) {
|
|
124
|
-
if (output.length > 0) {
|
|
125
|
-
console.log('\n' + output.trim() + '\n')
|
|
126
|
-
}
|
|
127
|
-
console.log(
|
|
128
|
-
chalk.bold.red('Compilation error! ') +
|
|
129
|
-
chalk.normal(`Please check ${this._name}.${this.extension()} and try again.`),
|
|
130
|
-
)
|
|
131
|
-
reject(new CompilationError('Compilation failed'))
|
|
132
|
-
} else {
|
|
133
|
-
resolve()
|
|
134
|
-
}
|
|
135
|
-
} catch (error) {
|
|
136
|
-
clearTimeout(timeout)
|
|
137
|
-
reject(error)
|
|
138
|
-
}
|
|
139
|
-
})()
|
|
140
|
-
})
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
protected async getVersion(cmd: string, lineIndex: number): Promise<string> {
|
|
144
|
-
try {
|
|
145
|
-
const proc = Bun.spawn(cmd.split(' '), {
|
|
146
|
-
stdout: 'pipe',
|
|
147
|
-
stderr: 'pipe',
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
const stdout = await new Response(proc.stdout).text()
|
|
151
|
-
const lines = stdout.split('\n')
|
|
152
|
-
return lines[lineIndex]?.trim() || 'Unknown version'
|
|
153
|
-
} catch {
|
|
154
|
-
return 'not found'
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
info(): CompilerInfo {
|
|
159
|
-
return {
|
|
160
|
-
compiler_id: this.id(),
|
|
161
|
-
name: this._name,
|
|
162
|
-
language: this.language(),
|
|
163
|
-
version: '', // Will be populated asynchronously
|
|
164
|
-
flags1: this.flags1(),
|
|
165
|
-
flags2: this.flags2(),
|
|
166
|
-
extension: this.extension(),
|
|
167
|
-
type: this.type(),
|
|
168
|
-
warning: this.warning(),
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
protected async timeExecution(cmd: string, iterations: number = 1): Promise<number> {
|
|
173
|
-
const start = Date.now()
|
|
174
|
-
for (let i = 0; i < iterations; i++) {
|
|
175
|
-
await $`sh -c ${cmd}`.quiet()
|
|
176
|
-
}
|
|
177
|
-
const end = Date.now()
|
|
178
|
-
return (end - start) / iterations / 1000 // Return in seconds
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Python3 Compiler
|
|
183
|
-
export class Compiler_Python3 extends Compiler {
|
|
184
|
-
name(): string {
|
|
185
|
-
return 'Python3'
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
type(): string {
|
|
189
|
-
return 'interpreter'
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
executable(): string {
|
|
193
|
-
return `${this._name}.py`
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
language(): string {
|
|
197
|
-
return 'Python'
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async version(): Promise<string> {
|
|
201
|
-
return await this.getVersion('python3 -V', 0)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
flags1(): string {
|
|
205
|
-
return ''
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
flags2(): string {
|
|
209
|
-
return ''
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
extension(): string {
|
|
213
|
-
return 'py'
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
private async genWrapper(): Promise<void> {
|
|
217
|
-
await Util.writeFile(
|
|
218
|
-
'py3c.py',
|
|
219
|
-
`#!/usr/bin/python3
|
|
220
|
-
|
|
221
|
-
import py_compile, sys
|
|
222
|
-
|
|
223
|
-
py_compile.compile(sys.argv[1])`,
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
private async delWrapper(): Promise<void> {
|
|
228
|
-
await Util.delFile('py3c.py')
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
async execute(tst: string, correct: boolean, iterations: number = 1): Promise<number> {
|
|
232
|
-
let exec = this.executable()
|
|
233
|
-
|
|
234
|
-
if (this.handler.source_modifier === 'no_main' || this.handler.source_modifier === 'structs') {
|
|
235
|
-
await Util.copyFile(`${this._name}.py`, 'modified.py')
|
|
236
|
-
const ori = await Util.readFile(`${this._name}.py`)
|
|
237
|
-
const main = await Util.readFile('main.py')
|
|
238
|
-
await Util.writeFile('modified.py', `${ori}\n${main}\n`)
|
|
239
|
-
exec = 'modified.py'
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
const ext = correct ? 'cor' : 'py.out'
|
|
243
|
-
const cmd = `python3 ${exec} < ${tst}.inp > ${tst}.${ext}`
|
|
244
|
-
|
|
245
|
-
if (correct) {
|
|
246
|
-
process.stdout.write(cmd)
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const time = await this.timeExecution(cmd, iterations)
|
|
250
|
-
|
|
251
|
-
await Util.delFile('modified.py')
|
|
252
|
-
await Util.delDir('__pycache__')
|
|
253
|
-
|
|
254
|
-
return time
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
async compile(): Promise<boolean> {
|
|
258
|
-
if (this.handler.source_modifier === 'no_main' || this.handler.source_modifier === 'structs') {
|
|
259
|
-
return await this.compileNoMain()
|
|
260
|
-
} else {
|
|
261
|
-
return await this.compileNormal()
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
private async compileNormal(): Promise<boolean> {
|
|
266
|
-
try {
|
|
267
|
-
await this.genWrapper()
|
|
268
|
-
const code = await Util.readFile(`${this._name}.py`)
|
|
269
|
-
await Util.writeFile(`${this._name}.py`, code)
|
|
270
|
-
await this.executeCompiler(`python3 py3c.py ${this._name}.py 1> /dev/null`)
|
|
271
|
-
} catch (error) {
|
|
272
|
-
if (error instanceof CompilationTooLongError) {
|
|
273
|
-
console.log(chalk.bold.red('Compilation time exceeded!'))
|
|
274
|
-
}
|
|
275
|
-
return false
|
|
276
|
-
} finally {
|
|
277
|
-
await this.delWrapper()
|
|
278
|
-
}
|
|
279
|
-
return true
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
private async compileNoMain(): Promise<boolean> {
|
|
283
|
-
if (!(await this.compileNormal())) {
|
|
284
|
-
return false
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
await Util.copyFile(`${this._name}.py`, 'modified.py')
|
|
288
|
-
const ori = await Util.readFile(`${this._name}.py`)
|
|
289
|
-
const main = await Util.readFile('main.py')
|
|
290
|
-
await Util.writeFile('modified.py', `${ori}\n${main}\n`)
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
await this.genWrapper()
|
|
294
|
-
await this.executeCompiler('python3 py3c.py modified.py 1> /dev/null')
|
|
295
|
-
} catch (error) {
|
|
296
|
-
if (error instanceof CompilationTooLongError) {
|
|
297
|
-
console.log(chalk.bold.red('Compilation time exceeded!'))
|
|
298
|
-
}
|
|
299
|
-
return false
|
|
300
|
-
} finally {
|
|
301
|
-
await this.delWrapper()
|
|
302
|
-
}
|
|
303
|
-
return true
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Compiler registry
|
|
308
|
-
const COMPILERS = ['GCC', 'GXX', 'Python3']
|
|
309
|
-
|
|
310
|
-
export function getCompiler(cpl: string, handler: Handler | null = null, name: string | null = null): Compiler {
|
|
311
|
-
const compilerClass = cpl.replace('++', 'XX')
|
|
312
|
-
|
|
313
|
-
switch (compilerClass) {
|
|
314
|
-
case 'GCC':
|
|
315
|
-
return new Compiler_GCC(handler, name)
|
|
316
|
-
case 'GXX':
|
|
317
|
-
return new Compiler_GXX(handler, name)
|
|
318
|
-
case 'Python3':
|
|
319
|
-
return new Compiler_Python3(handler, name)
|
|
320
|
-
default:
|
|
321
|
-
throw new Error(`Unknown compiler: ${cpl}`)
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
export async function getCompilerExtensions(handlerCompiler: string): Promise<Record<string, string>> {
|
|
326
|
-
const result: Record<string, string> = {}
|
|
327
|
-
|
|
328
|
-
for (const compilerName of COMPILERS) {
|
|
329
|
-
const compiler = getCompiler(compilerName)
|
|
330
|
-
const ext = compiler.extension()
|
|
331
|
-
|
|
332
|
-
if (compilerName === handlerCompiler) {
|
|
333
|
-
result[ext] = compilerName
|
|
334
|
-
} else if (!compilerName.includes('Run') && !(ext in result)) {
|
|
335
|
-
result[ext] = compilerName
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return result
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
export async function getAvailableCompilers(): Promise<string[]> {
|
|
343
|
-
const available: string[] = []
|
|
344
|
-
|
|
345
|
-
for (const compilerName of COMPILERS) {
|
|
346
|
-
const compiler = getCompiler(compilerName)
|
|
347
|
-
const version = await compiler.version()
|
|
348
|
-
|
|
349
|
-
if (!version.includes('not found')) {
|
|
350
|
-
available.push(compilerName)
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return available
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
export async function printAvailableCompilers(): Promise<void> {
|
|
358
|
-
const available = await getAvailableCompilers()
|
|
359
|
-
|
|
360
|
-
if (available.length > 0) {
|
|
361
|
-
process.stdout.write('Available compilers: ')
|
|
362
|
-
|
|
363
|
-
for (let i = 0; i < available.length; i++) {
|
|
364
|
-
process.stdout.write(available[i])
|
|
365
|
-
|
|
366
|
-
if (i === available.length - 2) {
|
|
367
|
-
process.stdout.write(' and ')
|
|
368
|
-
} else if (i !== available.length - 1) {
|
|
369
|
-
process.stdout.write(', ')
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
console.log()
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
export async function getCompilerInfo(): Promise<Record<string, CompilerInfo>> {
|
|
378
|
-
const result: Record<string, CompilerInfo> = {}
|
|
379
|
-
|
|
380
|
-
for (const compilerName of COMPILERS) {
|
|
381
|
-
const compiler = getCompiler(compilerName)
|
|
382
|
-
const info = compiler.info()
|
|
383
|
-
info.version = await compiler.version()
|
|
384
|
-
result[compilerName] = info
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
return result
|
|
388
|
-
}
|
package/lib/compilers/base.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { rm, exists } from 'fs/promises'
|
|
2
|
-
import { join, sep } from 'path'
|
|
3
|
-
import * as tui from '@/lib/tui'
|
|
4
|
-
|
|
5
|
-
export type CompilerInfo = {
|
|
6
|
-
compiler_id: string
|
|
7
|
-
name: string
|
|
8
|
-
language: string
|
|
9
|
-
version: string
|
|
10
|
-
flags1: string
|
|
11
|
-
flags2: string
|
|
12
|
-
extension: string
|
|
13
|
-
type: string
|
|
14
|
-
warning: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export abstract class Compiler {
|
|
18
|
-
abstract id(): string
|
|
19
|
-
|
|
20
|
-
abstract name(): string
|
|
21
|
-
|
|
22
|
-
abstract type(): string
|
|
23
|
-
|
|
24
|
-
abstract language(): string
|
|
25
|
-
|
|
26
|
-
abstract version(): Promise<string>
|
|
27
|
-
|
|
28
|
-
abstract flags1(): string
|
|
29
|
-
|
|
30
|
-
abstract flags2(): string
|
|
31
|
-
|
|
32
|
-
abstract extension(): string
|
|
33
|
-
|
|
34
|
-
warning(): string {
|
|
35
|
-
return ''
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async available(): Promise<boolean> {
|
|
39
|
-
const version = await this.version()
|
|
40
|
-
return version !== 'not found'
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async info(): Promise<CompilerInfo> {
|
|
44
|
-
return {
|
|
45
|
-
compiler_id: this.id(),
|
|
46
|
-
name: this.name(),
|
|
47
|
-
language: this.language(),
|
|
48
|
-
version: await this.version(),
|
|
49
|
-
flags1: this.flags1(),
|
|
50
|
-
flags2: this.flags2(),
|
|
51
|
-
extension: this.extension(),
|
|
52
|
-
type: this.type(),
|
|
53
|
-
warning: this.warning(),
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
abstract compile(directory: string, sourcePath: string): Promise<void>
|
|
58
|
-
|
|
59
|
-
// Default implementation of execute for compiled languages
|
|
60
|
-
async execute(directory: string, inputPath: string, outputPath: string): Promise<void> {
|
|
61
|
-
const executablePath = `solution.${this.extension()}.exe`
|
|
62
|
-
if (!(await exists(join(directory, executablePath)))) {
|
|
63
|
-
throw new Error(`Executable file ${executablePath} does not exist in directory ${directory}`)
|
|
64
|
-
}
|
|
65
|
-
// TODO: check in windows
|
|
66
|
-
const relativeExecutablePath = `.${sep}${executablePath}` // force prepending ./ to make it work
|
|
67
|
-
const fullInputPath = join(directory, inputPath)
|
|
68
|
-
const fullOutputPath = join(directory, outputPath)
|
|
69
|
-
await rm(fullOutputPath, { force: true })
|
|
70
|
-
tui.command(`${relativeExecutablePath} < ${inputPath} > ${outputPath}`)
|
|
71
|
-
const proc = Bun.spawn([relativeExecutablePath], {
|
|
72
|
-
cwd: directory,
|
|
73
|
-
stdin: Bun.file(fullInputPath),
|
|
74
|
-
stdout: Bun.file(fullOutputPath),
|
|
75
|
-
stderr: 'inherit',
|
|
76
|
-
})
|
|
77
|
-
await proc.exited
|
|
78
|
-
const exitCode = proc.exitCode
|
|
79
|
-
|
|
80
|
-
if (exitCode !== 0) throw new Error(`Execution failed for ${executablePath} with exit code ${exitCode}`)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
protected async getVersion(cmd: string, lineIndex: number): Promise<string> {
|
|
84
|
-
try {
|
|
85
|
-
const proc = Bun.spawn(cmd.split(' '), {
|
|
86
|
-
stdout: 'pipe',
|
|
87
|
-
stderr: 'pipe',
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
const stdout = await new Response(proc.stdout).text()
|
|
91
|
-
const lines = stdout.split('\n')
|
|
92
|
-
return lines[lineIndex]?.trim() || 'Unknown version'
|
|
93
|
-
} catch {
|
|
94
|
-
return 'not found'
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
package/lib/compilers/gcc.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import * as tui from '@/lib/tui.js'
|
|
2
|
-
import { Compiler } from './base'
|
|
3
|
-
import { rm, exists } from 'fs/promises'
|
|
4
|
-
import { join } from 'path'
|
|
5
|
-
|
|
6
|
-
export class Compiler_GCC extends Compiler {
|
|
7
|
-
id(): string {
|
|
8
|
-
return 'GCC'
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
name(): string {
|
|
12
|
-
return 'GNU C Compiler'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type(): string {
|
|
16
|
-
return 'compiler'
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
language(): string {
|
|
20
|
-
return 'C'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async version(): Promise<string> {
|
|
24
|
-
return await this.getVersion('gcc --version', 0)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
flags1(): string {
|
|
28
|
-
return '-D_JUDGE_ -O2 -DNDEBUG -Wall -Wextra -Wno-sign-compare'
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
flags2(): string {
|
|
32
|
-
return ''
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
extension(): string {
|
|
36
|
-
return 'c'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async compile(directory: string, sourcePath: string): Promise<void> {
|
|
40
|
-
const outputPath = sourcePath + '.exe'
|
|
41
|
-
const fullOutputPath = join(directory, outputPath)
|
|
42
|
-
await rm(fullOutputPath, { force: true })
|
|
43
|
-
tui.command(`gcc ${this.flags1()} ${sourcePath} -o ${outputPath}`)
|
|
44
|
-
await Bun.$`gcc ${this.flags1().split(' ')} ${sourcePath} -o ${outputPath}`.cwd(directory).nothrow()
|
|
45
|
-
if (!(await exists(fullOutputPath))) throw new Error(`Compilation failed for ${sourcePath}`)
|
|
46
|
-
}
|
|
47
|
-
}
|
package/lib/compilers/gxx.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { rm, exists } from 'fs/promises'
|
|
2
|
-
import { Compiler } from './base'
|
|
3
|
-
import chalk from 'chalk'
|
|
4
|
-
import { join } from 'path'
|
|
5
|
-
|
|
6
|
-
export class Compiler_GXX extends Compiler {
|
|
7
|
-
id(): string {
|
|
8
|
-
return 'GXX'
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
name(): string {
|
|
12
|
-
return 'GNU C++ Compiler'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type(): string {
|
|
16
|
-
return 'compiler'
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
language(): string {
|
|
20
|
-
return 'C++'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async version(): Promise<string> {
|
|
24
|
-
return await this.getVersion('g++ --version', 0)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
flags1(): string {
|
|
28
|
-
return '-std=c++11 -D_JUDGE_ -O2 -DNDEBUG -Wall -Wextra -Wno-sign-compare -Wshadow'
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
flags2(): string {
|
|
32
|
-
return '-std=c++11 -D_JUDGE_ -O2 -DNDEBUG -Wall -Wextra -Wno-sign-compare -Wshadow'
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
extension(): string {
|
|
36
|
-
return 'cc'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async compile(directory: string, sourcePath: string): Promise<void> {
|
|
40
|
-
const outputPath = sourcePath + '.exe'
|
|
41
|
-
const fullOutputPath = join(directory, outputPath)
|
|
42
|
-
await rm(fullOutputPath, { force: true })
|
|
43
|
-
console.log(chalk.magenta(`❯ g++ ${this.flags1()} ${sourcePath} -o ${outputPath}`))
|
|
44
|
-
await Bun.$`g++ ${this.flags1().split(' ')} ${sourcePath} -o ${outputPath}`.cwd(directory).nothrow()
|
|
45
|
-
if (!(await exists(fullOutputPath))) throw new Error(`Compilation failed for ${sourcePath}`)
|
|
46
|
-
}
|
|
47
|
-
}
|
package/lib/compilers/index.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { Compiler, type CompilerInfo } from './base'
|
|
2
|
-
import { Compiler_GCC } from './gcc'
|
|
3
|
-
import { Compiler_GXX } from './gxx'
|
|
4
|
-
import { Compiler_Python3 } from './python3'
|
|
5
|
-
|
|
6
|
-
const compilersRegistryById: Record<string, new () => Compiler> = {
|
|
7
|
-
C: Compiler_GCC,
|
|
8
|
-
'C++': Compiler_GXX,
|
|
9
|
-
Python3: Compiler_Python3,
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const compilersRegistryByExtension: Record<string, new () => Compiler> = {
|
|
13
|
-
c: Compiler_GCC,
|
|
14
|
-
cc: Compiler_GXX,
|
|
15
|
-
py: Compiler_Python3,
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function getCompilerById(id: string): Compiler {
|
|
19
|
-
const CompilerClass = compilersRegistryById[id]
|
|
20
|
-
if (!CompilerClass) throw new Error(`Compiler '${id}' is not defined`)
|
|
21
|
-
const compilerInstance = new CompilerClass()
|
|
22
|
-
return compilerInstance
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function getCompilerByExtension(extension: string): Compiler {
|
|
26
|
-
const CompilerClass = compilersRegistryByExtension[extension]
|
|
27
|
-
if (!CompilerClass) throw new Error(`No compiler defined for extension '.${extension}'`)
|
|
28
|
-
const compilerInstance = new CompilerClass()
|
|
29
|
-
return compilerInstance
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export async function getDefinedCompilerIds(): Promise<string[]> {
|
|
33
|
-
await Bun.sleep(0) // to make function async
|
|
34
|
-
return Object.keys(compilersRegistryById)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export async function getAvailableCompilers(): Promise<string[]> {
|
|
38
|
-
const available: string[] = []
|
|
39
|
-
for (const id of Object.keys(compilersRegistryById)) {
|
|
40
|
-
const CompilerClass = compilersRegistryById[id]!
|
|
41
|
-
const compilerInstance = new CompilerClass()
|
|
42
|
-
if (await compilerInstance.available()) {
|
|
43
|
-
available.push(id)
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return available
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export async function getCompilerInfo(id: string): Promise<CompilerInfo> {
|
|
50
|
-
const compilerInstance = getCompilerById(id)
|
|
51
|
-
if (!compilerInstance) throw new Error(`Compiler '${id}' is not defined`)
|
|
52
|
-
return await compilerInstance.info()
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export async function getCompilersInfo(): Promise<Record<string, CompilerInfo>> {
|
|
56
|
-
const infos: Record<string, CompilerInfo> = {}
|
|
57
|
-
for (const id of Object.keys(compilersRegistryById)) {
|
|
58
|
-
infos[id] = await getCompilerInfo(id)
|
|
59
|
-
}
|
|
60
|
-
return infos
|
|
61
|
-
}
|
package/lib/compilers/python3.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import * as tui from '@/lib/tui.js'
|
|
2
|
-
import { exists, rm } from 'fs/promises'
|
|
3
|
-
import { join } from 'path'
|
|
4
|
-
import { Compiler } from './base'
|
|
5
|
-
|
|
6
|
-
export class Compiler_Python3 extends Compiler {
|
|
7
|
-
id(): string {
|
|
8
|
-
return 'Python3'
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
name(): string {
|
|
12
|
-
return 'Python3'
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type(): string {
|
|
16
|
-
return 'interpreter'
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
language(): string {
|
|
20
|
-
return 'Python'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async version(): Promise<string> {
|
|
24
|
-
return await this.getVersion('python3 --version', 0)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
flags1(): string {
|
|
28
|
-
return ''
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
flags2(): string {
|
|
32
|
-
return ''
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
extension(): string {
|
|
36
|
-
return 'py'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async compile(directory: string, sourcePath: string): Promise<void> {
|
|
40
|
-
tui.command(`python3 -m py_compile ${sourcePath}`)
|
|
41
|
-
console.log('directory:', directory, 'sourcePath:', sourcePath)
|
|
42
|
-
const { exitCode } = await Bun.$`python3 -m py_compile ${sourcePath}`.cwd(directory).nothrow()
|
|
43
|
-
if (exitCode !== 0) throw new Error(`Compilation failed for ${sourcePath}`)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
override async execute(directory: string, inputPath: string, outputPath: string): Promise<void> {
|
|
47
|
-
const sourcePath = 'solution.py'
|
|
48
|
-
if (!(await exists(join(directory, sourcePath)))) {
|
|
49
|
-
throw new Error(`Source file ${sourcePath} does not exist in directory ${directory}`)
|
|
50
|
-
}
|
|
51
|
-
const fullInputPath = join(directory, inputPath)
|
|
52
|
-
const fullOutputPath = join(directory, outputPath)
|
|
53
|
-
await rm(fullOutputPath, { force: true })
|
|
54
|
-
tui.command(`python3 ${sourcePath} < ${inputPath} > ${outputPath}`)
|
|
55
|
-
|
|
56
|
-
const proc = Bun.spawn(['python3', sourcePath], {
|
|
57
|
-
cwd: directory,
|
|
58
|
-
stdin: Bun.file(fullInputPath),
|
|
59
|
-
stdout: Bun.file(fullOutputPath),
|
|
60
|
-
stderr: 'inherit',
|
|
61
|
-
})
|
|
62
|
-
await proc.exited
|
|
63
|
-
const exitCode = proc.exitCode
|
|
64
|
-
|
|
65
|
-
if (exitCode !== 0) throw new Error(`Execution failed for ${sourcePath}`)
|
|
66
|
-
}
|
|
67
|
-
}
|