From e5ff9178a024d1dbc10a42d963f99e03f690b4b0 Mon Sep 17 00:00:00 2001 From: jorg-vr Date: Wed, 16 Oct 2024 14:57:02 +0200 Subject: [PATCH] Improve linting --- tested/languages/c/config.py | 2 +- tested/languages/c/generators.py | 35 ++++----- tested/languages/cpp/config.py | 18 +++-- tested/languages/cpp/generators.py | 110 ++++++++++++++++++++--------- tested/manual.py | 6 +- 5 files changed, 111 insertions(+), 60 deletions(-) diff --git a/tested/languages/c/config.py b/tested/languages/c/config.py index f6fa9ff4..4ec853f1 100644 --- a/tested/languages/c/config.py +++ b/tested/languages/c/config.py @@ -140,7 +140,7 @@ def cleanup_stacktrace(self, stacktrace: str) -> str: def is_source_file(self, file: Path) -> bool: return file.suffix in (".c", ".h") - + def generator(self) -> CGenerator: return CGenerator(self.file_extension()) diff --git a/tested/languages/c/generators.py b/tested/languages/c/generators.py index 224bf453..cc84d52f 100644 --- a/tested/languages/c/generators.py +++ b/tested/languages/c/generators.py @@ -34,13 +34,15 @@ ) from tested.testsuite import MainInput + class CGenerator: def __init__(self, extension: str = "c"): self.extension = extension def convert_arguments(self, arguments: list[Expression | NamedArgument]) -> str: - return ", ".join(self.convert_statement(cast(Expression, arg)) for arg in arguments) - + return ", ".join( + self.convert_statement(cast(Expression, arg)) for arg in arguments + ) def convert_value(self, value: Value) -> str: # Handle some advanced types. @@ -67,7 +69,9 @@ def convert_value(self, value: Value) -> str: else: return str(value.data) elif value.type == BasicNumericTypes.REAL: - suffix = "f" if original.type == AdvancedNumericTypes.SINGLE_PRECISION else "" + suffix = ( + "f" if original.type == AdvancedNumericTypes.SINGLE_PRECISION else "" + ) if not isinstance(value.data, SpecialNumbers): return str(value.data) + suffix elif value.data == SpecialNumbers.NOT_A_NUMBER: @@ -94,14 +98,14 @@ def convert_value(self, value: Value) -> str: return convert_unknown_type(value) raise AssertionError(f"Invalid literal: {value!r}") - def convert_function_call(self, function: FunctionCall) -> str: result = function.name if function.type != FunctionType.PROPERTY: - result += f"({self.convert_arguments(function.arguments)})" # pyright: ignore + result += ( + f"({self.convert_arguments(function.arguments)})" # pyright: ignore + ) return result - def convert_declaration(self, tp: AllTypes | VariableType) -> str: if isinstance(tp, VariableType): return tp.data @@ -144,7 +148,6 @@ def convert_declaration(self, tp: AllTypes | VariableType) -> str: return "void" raise AssertionError(f"Unknown type: {tp!r}") - def convert_statement(self, statement: Statement, full=False) -> str: if isinstance(statement, Identifier): return statement @@ -162,7 +165,7 @@ def convert_statement(self, statement: Statement, full=False) -> str: f"{self.convert_statement(statement.expression)};" ) raise AssertionError(f"Unknown statement: {statement!r}") - + def convert_testcase(self, tc: PreparedTestcase, pu: PreparedExecutionUnit) -> str: result = "" if tc.testcase.is_main_testcase(): @@ -184,13 +187,16 @@ def convert_testcase(self, tc: PreparedTestcase, pu: PreparedExecutionUnit) -> s + self.convert_statement(tc.input.unwrapped_input_statement()) + ";\n" ) - result += " " * 4 + self.convert_statement(tc.input.no_value_call()) + ";\n" + result += ( + " " * 4 + self.convert_statement(tc.input.no_value_call()) + ";\n" + ) else: result += self.convert_statement(tc.input.input_statement()) + ";\n" return result - - def generate_internal_context(self, ctx: PreparedContext, pu: PreparedExecutionUnit) -> str: + def generate_internal_context( + self, ctx: PreparedContext, pu: PreparedExecutionUnit + ) -> str: result = f""" {ctx.before} @@ -202,11 +208,11 @@ def generate_internal_context(self, ctx: PreparedContext, pu: PreparedExecutionU for tc in ctx.testcases: result += f"{pu.unit.name}_write_separator();\n" result += self.convert_testcase(tc, pu) - + result += ctx.after + "\n" result += "return exit_code;\n" return result - + def define_write_funtions(self, pu: PreparedExecutionUnit) -> str: return f""" static FILE* {pu.unit.name}_value_file = NULL; @@ -233,7 +239,6 @@ def define_write_funtions(self, pu: PreparedExecutionUnit) -> str: #define send_specific_value(value) write_evaluated({pu.unit.name}_value_file, value) """ - def convert_execution_unit(self, pu: PreparedExecutionUnit) -> str: result = f""" #include @@ -283,7 +288,6 @@ def convert_execution_unit(self, pu: PreparedExecutionUnit) -> str: """ return result - def convert_selector(self, contexts: list[str]) -> str: result = """ #include @@ -325,7 +329,6 @@ def convert_selector(self, contexts: list[str]) -> str: """ return result - def convert_encoder(self, values: list[Value]) -> str: result = """ #include diff --git a/tested/languages/cpp/config.py b/tested/languages/cpp/config.py index fecb52c0..7e3b36e5 100644 --- a/tested/languages/cpp/config.py +++ b/tested/languages/cpp/config.py @@ -1,6 +1,7 @@ from pathlib import Path -from tested.features import Construct, TypeSupport + from tested.datatypes import AllTypes +from tested.features import Construct, TypeSupport from tested.languages.c.config import C from tested.languages.conventionalize import Conventionable, NamingConventions from tested.languages.cpp.generators import CPPGenerator @@ -10,18 +11,23 @@ class CPP(C): def initial_dependencies(self) -> list[str]: - return ["values.h", "values.cpp", "values.tpp", "evaluation_result.h", "evaluation_result.cpp"] + return [ + "values.h", + "values.cpp", + "values.tpp", + "evaluation_result.h", + "evaluation_result.cpp", + ] def file_extension(self) -> str: return "cpp" - + def naming_conventions(self) -> dict[Conventionable, NamingConventions]: return { "identifier": "camel_case", "property": "camel_case", "class": "pascal_case", "global_identifier": "macro_case", - } def supported_constructs(self) -> set[Construct]: @@ -32,9 +38,9 @@ def supported_constructs(self) -> set[Construct]: Construct.OBJECTS, Construct.HETEROGENEOUS_COLLECTIONS, Construct.DEFAULT_PARAMETERS, - Construct.HETEROGENEOUS_ARGUMENTS + Construct.HETEROGENEOUS_ARGUMENTS, } - + def datatype_support(self) -> dict[AllTypes, TypeSupport]: return super().datatype_support() | { # type: ignore "sequence": "supported", diff --git a/tested/languages/cpp/generators.py b/tested/languages/cpp/generators.py index 1afc2022..67b031b3 100644 --- a/tested/languages/cpp/generators.py +++ b/tested/languages/cpp/generators.py @@ -1,14 +1,43 @@ - from tested.datatypes import AllTypes, resolve_to_basic -from tested.datatypes.advanced import AdvancedNumericTypes, AdvancedObjectTypes, AdvancedSequenceTypes, AdvancedStringTypes -from tested.datatypes.basic import BasicNumericTypes, BasicObjectTypes, BasicSequenceTypes, BasicStringTypes, BasicTypes +from tested.datatypes.advanced import ( + AdvancedNumericTypes, + AdvancedObjectTypes, + AdvancedSequenceTypes, + AdvancedStringTypes, +) +from tested.datatypes.basic import ( + BasicNumericTypes, + BasicObjectTypes, + BasicSequenceTypes, + BasicStringTypes, + BasicTypes, +) from tested.languages.c.generators import CGenerator -from tested.languages.preparation import PreparedContext, PreparedExecutionUnit, PreparedFunctionCall, PreparedTestcase, PreparedTestcaseStatement -from tested.serialisation import FunctionCall, FunctionType, ObjectType, PropertyAssignment, SequenceType, Statement, Value, VariableAssignment, VariableType, WrappedAllTypes +from tested.languages.preparation import ( + PreparedContext, + PreparedExecutionUnit, + PreparedFunctionCall, + PreparedTestcase, + PreparedTestcaseStatement, +) +from tested.serialisation import ( + FunctionCall, + FunctionType, + ObjectType, + PropertyAssignment, + SequenceType, + Statement, + Value, + VariableAssignment, + VariableType, + WrappedAllTypes, +) class CPPGenerator(CGenerator): - def unpack_wrapped_types(self, type_or_types: WrappedAllTypes) -> tuple[AllTypes, WrappedAllTypes]: + def unpack_wrapped_types( + self, type_or_types: WrappedAllTypes + ) -> tuple[AllTypes, WrappedAllTypes]: if isinstance(type_or_types, tuple): return type_or_types return type_or_types, None @@ -26,8 +55,10 @@ def convert_sequence_subtype(self, value: Statement, subtype: AllTypes) -> str: tp, subtype = self.unpack_wrapped_types(type_or_types) return self.convert_declaration(tp, None, subtype) - - def convert_map_subtypes(self, value: Statement, subtype: WrappedAllTypes) -> tuple[str, str] | None: + + def convert_map_subtypes( + self, value: Statement, subtype: WrappedAllTypes + ) -> tuple[str, str] | None: if isinstance(value, ObjectType): key_type = value.get_key_type() value_type = value.get_value_type() @@ -41,24 +72,32 @@ def convert_map_subtypes(self, value: Statement, subtype: WrappedAllTypes) -> tu value_type_str = self.convert_declaration(value_base_type, None, value_sub_type) return key_type_str, value_type_str - + def convert_value(self, value: Value) -> str: tp = value.type basic = resolve_to_basic(tp) if basic == BasicObjectTypes.MAP: - return "{" + ", ".join(f"{self.convert_value(k), self.convert_value(v)}" for k, v in value.data.items()) + "}" + return ( + "{" + + ", ".join( + f"{self.convert_value(k), self.convert_value(v)}" + for k, v in value.data.items() + ) + + "}" + ) elif basic == BasicSequenceTypes.SEQUENCE or basic == BasicSequenceTypes.SET: return "{" + ", ".join(self.convert_value(v) for v in value.data) + "}" elif basic == BasicStringTypes.TEXT: return f'std::string("{value.data}")' return super().convert_value(value) - - - def convert_declaration(self, tp: AllTypes | VariableType, - value: Statement | None = None, - subtype: WrappedAllTypes| None = None) -> str: + def convert_declaration( + self, + tp: AllTypes | VariableType, + value: Statement | None = None, + subtype: WrappedAllTypes | None = None, + ) -> str: if isinstance(tp, VariableType): return tp.data + "*" elif tp == AdvancedNumericTypes.BIG_INT: @@ -95,7 +134,7 @@ def convert_declaration(self, tp: AllTypes | VariableType, return f"std::vector<{subtype}>" elif tp == AdvancedStringTypes.STRING: return "std::string" - + basic = resolve_to_basic(tp) if basic == BasicObjectTypes.MAP: key_type, value_type = self.convert_map_subtypes(value, subtype) @@ -113,20 +152,19 @@ def convert_declaration(self, tp: AllTypes | VariableType, elif basic == BasicNumericTypes.INTEGER: return "std::intmax_t" - return super().convert_declaration(tp) - + def convert_statement(self, statement: Statement, full=False) -> str: # support for property assignments if isinstance(statement, PropertyAssignment): - return ( - f"{self.convert_statement(statement.property)} = " - f"{self.convert_statement(statement.expression)};" - ) + return ( + f"{self.convert_statement(statement.property)} = " + f"{self.convert_statement(statement.expression)};" + ) # overwrite the default implementation for variable assignments to allow for # object declarations elif full and isinstance(statement, VariableAssignment): - + prefix = self.convert_declaration(statement.type, statement.expression) return ( f"{prefix} {statement.variable} = " @@ -134,40 +172,44 @@ def convert_statement(self, statement: Statement, full=False) -> str: ) return super().convert_statement(statement, full) - + def convert_function_call(self, function: FunctionCall) -> str: result = super().convert_function_call(function) # if the function has a namespace, that is not the root namespace we assume it is a method call - if (function.namespace + if ( + function.namespace and not function.has_root_namespace and not function.type == FunctionType.CONSTRUCTOR - ): + ): result = self.convert_statement(function.namespace) + "->" + result # add the new keyword to constructors if function.type == FunctionType.CONSTRUCTOR: result = "new " + result return result - + def convert_testcase(self, tc: PreparedTestcase, pu: PreparedExecutionUnit) -> str: result = "" # Define variables before asignment outside the try block - if ( not tc.testcase.is_main_testcase() - and isinstance(tc.input, PreparedTestcaseStatement) - and isinstance(tc.input.statement, VariableAssignment) + if ( + not tc.testcase.is_main_testcase() + and isinstance(tc.input, PreparedTestcaseStatement) + and isinstance(tc.input.statement, VariableAssignment) ): - prefix = self.convert_declaration(tc.input.statement.type, tc.input.statement.expression) + prefix = self.convert_declaration( + tc.input.statement.type, tc.input.statement.expression + ) result += f"{prefix} {tc.input.statement.variable};\n" - + # catch exceptions and write them to the output result += "try {" + "\n" result += super().convert_testcase(tc, pu) result += "\n} catch (std::exception_ptr e) {\n" - result += self.convert_statement(tc.exception_statement('e'))+ ";\n" + result += self.convert_statement(tc.exception_statement("e")) + ";\n" result += "exit_code = 1;\n" result += "}\n" return result - + def define_write_funtions(self, pu: PreparedExecutionUnit) -> str: result = super().define_write_funtions(pu) diff --git a/tested/manual.py b/tested/manual.py index ad1dc353..adcbcf29 100644 --- a/tested/manual.py +++ b/tested/manual.py @@ -13,7 +13,7 @@ from tested.main import run from tested.testsuite import SupportedLanguage -exercise_dir = "/home/jorg/Documents/universal-judge/tests/exercises/echo" +exercise_dir = "/home/jorg/Documents/universal-judge/tests/exercises/echo-function" def read_config() -> DodonaConfig: @@ -24,10 +24,10 @@ def read_config() -> DodonaConfig: programming_language=SupportedLanguage("cpp"), natural_language="nl", resources=Path(exercise_dir, "evaluation"), - source=Path(exercise_dir, "solution/run-error.cpp"), + source=Path(exercise_dir, "solution/correct.cpp"), judge=Path("."), workdir=Path("workdir"), - test_suite="two.tson", + test_suite="expected_no_return_and_got_none.yaml", options=Options( linter=False, ),