Skip to content

Commit

Permalink
Get first c++ judgements up and running
Browse files Browse the repository at this point in the history
  • Loading branch information
jorg-vr committed Jul 17, 2024
1 parent 35b6314 commit 5cec4da
Show file tree
Hide file tree
Showing 13 changed files with 590 additions and 4 deletions.
2 changes: 2 additions & 0 deletions tested/languages/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

from tested.languages.bash.config import Bash
from tested.languages.c.config import C
from tested.languages.cpp.config import CPP
from tested.languages.csharp.config import CSharp
from tested.languages.haskell.config import Haskell
from tested.languages.java.config import Java
Expand All @@ -34,6 +35,7 @@
"python": Python,
"runhaskell": RunHaskell,
"csharp": CSharp,
"cpp": CPP,
}


Expand Down
43 changes: 43 additions & 0 deletions tested/languages/cpp/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from pathlib import Path
import re

from tested.languages.c.config import C
from tested.languages.language import CallbackResult
from tested.languages.preparation import PreparedExecutionUnit
from tested.languages.utils import executable_name


class CPP(C):
def initial_dependencies(self) -> list[str]:
return ["values.h", "values.cpp", "evaluation_result.h", "evaluation_result.cpp"]

def file_extension(self) -> str:
return "cpp"

def compilation(self, files: list[str]) -> CallbackResult:
main_file = files[-1]
exec_file = Path(main_file).stem
result = executable_name(exec_file)
return (
[
"g++",
"-std=c++11",
"-Wall",
"-O3" if self.config.options.compiler_optimizations else "-O0",
"evaluation_result.cpp",
"values.cpp",
main_file,
"-o",
result,
],
[result],
)

def generate_execution_unit(self, execution_unit: "PreparedExecutionUnit") -> str:
from tested.languages.cpp import generators
return generators.convert_execution_unit(execution_unit)

def generate_selector(self, contexts: list[str]) -> str:
from tested.languages.cpp import generators

return generators.convert_selector(contexts)
170 changes: 170 additions & 0 deletions tested/languages/cpp/generators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import json

from tested.languages.c.generators import convert_statement
from tested.languages.preparation import PreparedExecutionUnit, PreparedContext, \
PreparedTestcase, PreparedTestcaseStatement
from tested.languages.utils import is_special_void_call
from tested.testsuite import MainInput


def _generate_internal_context(ctx: PreparedContext, pu: PreparedExecutionUnit) -> str:
result = f"""
{ctx.before}
int exit_code;
"""

# Generate code for each testcase
tc: PreparedTestcase
for tc in ctx.testcases:
result += f"{pu.unit.name}_write_separator();\n"

if tc.testcase.is_main_testcase():
assert isinstance(tc.input, MainInput)
wrapped = [json.dumps(a) for a in tc.input.arguments]
result += f'string string_args[] = {{"{pu.submission_name}", '
result += ", ".join(wrapped)
result += "};\n"
result += f"""
// convert string to char**
const int argc = {len(tc.input.arguments) + 1};
char** args = new char*[argc];
for (int i = 0; i < argc; i++) {{
args[i] = new char[string_args[i].size() + 1];
strcpy(args[i], string_args[i].c_str());
}}
"""
result += (
f"exit_code = solution_main(argc, args);\n"
)
else:
assert isinstance(tc.input, PreparedTestcaseStatement)
result += "exit_code = 0;\n"
if is_special_void_call(tc.input, pu.language):
# The method has a "void" return type, so don't wrap it.
result += (
" " * 4
+ convert_statement(tc.input.unwrapped_input_statement())
+ ";\n"
)
result += " " * 4 + convert_statement(tc.input.no_value_call()) + ";\n"
else:
result += convert_statement(tc.input.input_statement()) + ";\n"

result += ctx.after + "\n"
result += "return exit_code;\n"
return result


def convert_execution_unit(pu: PreparedExecutionUnit) -> str:
result = f"""
#include "values.h"
#include "{pu.submission_name}.cpp"
using namespace std;
"""

# Import functions
for name in pu.evaluator_names:
result += f'#include "{name}.cpp"\n'

result += f"""
static FILE* {pu.unit.name}_value_file = NULL;
static FILE* {pu.unit.name}_exception_file = NULL;
static void {pu.unit.name}_write_separator() {{
fprintf({pu.unit.name}_value_file, "--{pu.testcase_separator_secret}-- SEP");
fprintf({pu.unit.name}_exception_file, "--{pu.testcase_separator_secret}-- SEP");
fprintf(stdout, "--{pu.testcase_separator_secret}-- SEP");
fprintf(stderr, "--{pu.testcase_separator_secret}-- SEP");
}}
static void {pu.unit.name}_write_context_separator() {{
fprintf({pu.unit.name}_value_file, "--{pu.context_separator_secret}-- SEP");
fprintf({pu.unit.name}_exception_file, "--{pu.context_separator_secret}-- SEP");
fprintf(stdout, "--{pu.context_separator_secret}-- SEP");
fprintf(stderr, "--{pu.context_separator_secret}-- SEP");
}}
#undef send_value
#define send_value(value) write_value({pu.unit.name}_value_file, value)
#undef send_specific_value
#define send_specific_value(value) write_evaluated({pu.unit.name}_value_file, value)
"""

# Generate code for each context.
ctx: PreparedContext
for i, ctx in enumerate(pu.contexts):
result += f"""
int {pu.unit.name}_context_{i}(void) {{
{_generate_internal_context(ctx, pu)}
}}
"""

result += f"""
int {pu.unit.name}() {{
{pu.unit.name}_value_file = fopen("{pu.value_file}", "w");
{pu.unit.name}_exception_file = fopen("{pu.exception_file}", "w");
int exit_code;
"""

for i, ctx in enumerate(pu.contexts):
result += " " * 4 + f"{pu.unit.name}_write_context_separator();\n"
result += " " * 4 + f"exit_code = {pu.unit.name}_context_{i}();\n"

result += f"""
fclose({pu.unit.name}_value_file);
fclose({pu.unit.name}_exception_file);
return exit_code;
}}
#ifndef INCLUDED
int main() {{
return {pu.unit.name}();
}}
#endif
"""
return result


def convert_selector(contexts: list[str]) -> str:
result = """
#include <string.h>
#include <stdio.h>
#define INCLUDED true
"""

for ctx in contexts:
result += f"""
#if __has_include("{ctx}.cpp")
#include "{ctx}.cpp"
#endif
"""

result += """
int main(int argc, const char* argv[]) {
if (argc < 1) {
fprintf(stderr, "No context selected.");
return -2;
}
const char* name = argv[1];
"""
for ctx in contexts:
result += f"""
#if __has_include("{ctx}.cpp")
if (strcmp("{ctx}", name) == 0) {{
return {ctx}();
}}
#endif
"""

result += """
fprintf(stderr, "Non-existing context '%s' selected.", name);
return -1;
}
"""
return result
49 changes: 49 additions & 0 deletions tested/languages/cpp/templates/evaluation_result.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <iostream>
#include <vector>
#include <string>

#include "evaluation_result.h"

// Define the Message constructor
Message::Message(const std::string &desc, const std::string &fmt, const std::string &perm)
: description(desc), format(fmt.empty() ? "text" : fmt), permission(perm) {}

// Define the EvaluationResult constructor
EvaluationResult::EvaluationResult(size_t nrOfMessages) {
messages.reserve(nrOfMessages);
}

// Define the EvaluationResult destructor
EvaluationResult::~EvaluationResult() {
for (auto message : messages) {
delete message;
}
}

// Function to create an EvaluationResult object
EvaluationResult* create_result(size_t nrOfMessages) {
return new EvaluationResult(nrOfMessages);
}

// Function to free an EvaluationResult object
void free_result(EvaluationResult *result) {
delete result;
}

// Function to create a Message object
Message* create_message(const std::string &description, const std::string &format, const std::string &permission) {
return new Message(description, format, permission);
}

// Function to free a Message object
void free_message(Message *message) {
delete message;
}








43 changes: 43 additions & 0 deletions tested/languages/cpp/templates/evaluation_result.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef EVALUATION_RESULT_H
#define EVALUATION_RESULT_H

#include <iostream>
#include <vector>
#include <string>

using namespace std;

// Define the Message structure
struct Message {
string description;
string format;
string permission;

Message(const string &desc, const string &fmt, const string &perm);
};

// Define the EvaluationResult structure
struct EvaluationResult {
vector<Message*> messages;
bool result;
string readableExpected;
string readableActual;

EvaluationResult(size_t nrOfMessages);
~EvaluationResult();
};


// Function to create an EvaluationResult object
EvaluationResult* create_result(size_t nrOfMessages);

// Function to free an EvaluationResult object
void free_result(EvaluationResult *result);

// Function to create a Message object
Message* create_message(const string &description, const string &format, const string &permission);

// Function to free a Message object
void free_message(Message *message);

#endif //EVALUATION_RESULT_H
Loading

0 comments on commit 5cec4da

Please sign in to comment.