Runtime: add Nim runner

Hooray!
This commit is contained in:
akp 2021-12-03 00:11:46 +00:00
parent 629fff4414
commit cb36157b56
No known key found for this signature in database
GPG key ID: AA5726202C8879B7
3 changed files with 140 additions and 0 deletions

View file

@ -0,0 +1,56 @@
import std/strutils
import std/options
import std/json
import std/monotimes
import std/times
from nim/challenge as solutions import nil
proc sendResult(taskID: string, ok: bool, output: string, duration: float64) =
let jobj = %* {
"task_id": taskID,
"ok": ok,
"output": output,
"duration": duration,
}
echo $jobj
type
Task = ref object
task_id: string
part: int
input: string
output_dir: Option[string]
let tasksString = readLine(stdin)
let tasks = to(parseJson(tasksString), seq[Task])
for _, task in tasks:
var runProc: proc(): string
case task.part
of 1:
runProc = proc(): string = $(solutions.partOne(task.input))
of 2:
runProc = proc(): string = $(solutions.partTwo(task.input))
else:
sendResult(task.task_id, false, "unknown task part", 0.0)
var
result: string
error: string
let startTime = getMonoTime()
try:
result = runProc()
except:
error = getCurrentExceptionMsg()
let endTime = getMonoTime()
let runningTime = endTime - startTime
let runningTimeSeconds = float(inNanoseconds(runningTime)) / float(1000000000)
if error != "":
sendResult(task.task_id, false, error, runningTimeSeconds)
else:
sendResult(task.task_id, true, result, runningTimeSeconds)

View file

@ -0,0 +1,82 @@
package runners
import (
"bytes"
_ "embed"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
)
const nimInstallation = "nim"
type nimRunner struct {
dir string
tasks []*Task
}
func newNimRunner(dir string) Runner {
return &nimRunner{
dir: dir,
}
}
func (n *nimRunner) Queue(task *Task) {
n.tasks = append(n.tasks, task)
}
//go:embed interface/nim.nim
var nimInterface []byte
func (n *nimRunner) Run() (chan ResultOrError, func()) {
wrapperExecutable := "runtimeWrapper"
wrapperFilename := wrapperExecutable + ".nim"
executableFilepath := filepath.Join(n.dir, wrapperExecutable)
wrapperFilepath := filepath.Join(n.dir, wrapperFilename)
// generate interaction data
taskJSON, err := json.Marshal(n.tasks)
if err != nil {
return makeErrorChan(err), nil
}
// save interaction code
err = ioutil.WriteFile(wrapperFilepath, nimInterface, 0644)
if err != nil {
return makeErrorChan(err), nil
}
// compile
stderrBuffer := new(bytes.Buffer)
cmd := exec.Command(nimInstallation, "compile", "-o:"+executableFilepath, "-d:release", wrapperFilepath)
cmd.Stderr = stderrBuffer
err = cmd.Run()
if err != nil {
return makeErrorChan(fmt.Errorf("compilation failed: %s: %s", err, stderrBuffer.String())), nil
}
if !cmd.ProcessState.Success() {
return makeErrorChan(errors.New("compilation failed, hence cannot continue")), nil
}
absExecPath, err := filepath.Abs(executableFilepath)
if err != nil {
return makeErrorChan(err), nil
}
// run
cmd = exec.Command(absExecPath)
cmd.Dir = n.dir
cmd.Stdin = bytes.NewReader(append(taskJSON, '\n'))
return readResultsFromCommand(cmd), func() {
_ = os.Remove(executableFilepath)
_ = os.Remove(wrapperFilepath)
}
}

View file

@ -23,9 +23,11 @@ type RunnerCreator func(dir string) Runner
var Available = map[string]RunnerCreator{
"py": newPythonRunner,
"go": newGolangRunner,
"nim": newNimRunner,
}
var RunnerNames = map[string]string{
"py": "Python",
"go": "Golang",
"nim": "Nim",
}