from logging import getLogger
from typing import *
import onlinejudge_template.analyzer.codeforces
import onlinejudge_template.analyzer.constants
import onlinejudge_template.analyzer.html
import onlinejudge_template.analyzer.minimum_tree
import onlinejudge_template.analyzer.output_types
import onlinejudge_template.analyzer.parser
import onlinejudge_template.analyzer.simple_patterns
import onlinejudge_template.analyzer.topcoder
import onlinejudge_template.analyzer.typing
import onlinejudge_template.analyzer.variables
from onlinejudge_template.types import *
logger = getLogger(__name__)
[docs]def prepare_from_html(html: bytes, *, url: str, sample_cases: Optional[List[SampleCase]] = None) -> AnalyzerResources:
input_format_string: Optional[str] = None
try:
input_format_string = onlinejudge_template.analyzer.html.parse_input_format_string(html, url=url)
logger.debug('input format string: %s', repr(input_format_string))
except AnalyzerError as e:
logger.info('failed to detect the input format string: %s', e)
except NotImplementedError as e:
logger.debug('The detection of input format strings is not supported for this problem: %s', e)
output_format_string: Optional[str] = None
try:
output_format_string = onlinejudge_template.analyzer.html.parse_output_format_string(html, url=url)
logger.debug('output format string: %s', repr(output_format_string))
except AnalyzerError as e:
logger.info('failed to detect the output format string: %s', e)
except NotImplementedError as e:
logger.debug('The detection of output format strings is not supported for this problem: %s', e)
resources = AnalyzerResources(
url=url,
html=html,
input_format_string=input_format_string,
output_format_string=output_format_string,
sample_cases=sample_cases,
)
return resources
[docs]def run(resources: AnalyzerResources) -> AnalyzerResult:
# It seems that topcoder_class_definition should be included in resources.
topcoder_class_definition: Optional[TopcoderClassDefinition] = None
try:
if resources.url is not None and onlinejudge_template.analyzer.topcoder.is_topcoder_url(resources.url):
if resources.html is not None:
topcoder_class_definition = onlinejudge_template.analyzer.topcoder.parse_topcoder_class_definition(resources.html, url=resources.url)
except AnalyzerError as e:
logger.exception('failed to analyze the class definition of the Topcoder problem: %s', e)
multiple_test_cases = False
try:
if resources.url is not None and onlinejudge_template.analyzer.codeforces.is_codeforces_url(resources.url):
if resources.html is not None:
multiple_test_cases = onlinejudge_template.analyzer.codeforces.has_multiple_testcases(resources.html, url=resources.url)
if multiple_test_cases:
logger.info('Each input of this problem has multiple test cases.')
except AnalyzerError as e:
logger.exception('failed to decide wheter the Codeforces problem has multiple test cases: %s', e)
# parse the format tree for input
input_format: Optional[FormatNode] = None
try:
if resources.input_format_string is not None:
input_format = onlinejudge_template.analyzer.parser.run(resources.input_format_string)
elif topcoder_class_definition is not None:
input_format = onlinejudge_template.analyzer.topcoder.convert_topcoder_class_definition_to_input_format(topcoder_class_definition)
except AnalyzerError as e:
logger.info('failed to parse the input format string: %s', e)
try:
if input_format is None and resources.sample_cases:
input_samples = [case.input.decode() for case in resources.sample_cases]
if not multiple_test_cases:
input_format = onlinejudge_template.analyzer.simple_patterns.guess_format_with_pattern_matching(instances=input_samples)
if input_format is None:
input_format = onlinejudge_template.analyzer.minimum_tree.construct_minimum_input_format_tree(instances=input_samples, multiple_test_cases=multiple_test_cases)
except AnalyzerError as e:
logger.info('failed to analyze the input format from the input sample cases: %s', e)
if input_format is None:
logger.info('failed to analyze the input format: all analyzers failed')
# list the variables for input
input_variables: Optional[Dict[VarName, VarDecl]] = None
try:
if resources.input_format_string is None and topcoder_class_definition is not None:
input_variables = onlinejudge_template.analyzer.topcoder.convert_topcoder_class_definition_to_input_variables(topcoder_class_definition)
elif input_format is not None:
input_variables = onlinejudge_template.analyzer.variables.list_declared_variables(input_format)
if input_format is not None and input_variables is not None and resources.sample_cases:
input_samples = [case.input.decode() for case in resources.sample_cases]
input_types = onlinejudge_template.analyzer.typing.infer_types_from_instances(input_format, variables=input_variables, instances=input_samples)
input_variables = onlinejudge_template.analyzer.typing.update_variables_with_types(variables=input_variables, types=input_types)
except AnalyzerError as e:
logger.info('failed to list variables in the input format: %s', e)
# parse the format tree for output
output_format: Optional[FormatNode] = None
try:
if resources.output_format_string is not None:
output_format = onlinejudge_template.analyzer.parser.run(resources.output_format_string)
elif topcoder_class_definition is not None:
output_format = onlinejudge_template.analyzer.topcoder.convert_topcoder_class_definition_to_output_format(topcoder_class_definition)
except AnalyzerError as e:
logger.info('failed to parse the output format string: %s', e)
try:
if output_format is None and resources.sample_cases:
if input_format is not None and input_variables is not None:
if not multiple_test_cases:
output_format = onlinejudge_template.analyzer.simple_patterns.guess_output_format_with_pattern_matching_using_input_format(instances=resources.sample_cases, input_format=input_format, input_variables=input_variables)
if output_format is None:
output_format = onlinejudge_template.analyzer.minimum_tree.construct_minimum_output_format_tree_using_input_format(instances=resources.sample_cases, input_format=input_format, input_variables=input_variables, multiple_test_cases=multiple_test_cases)
else:
output_samples = [case.output.decode() for case in resources.sample_cases]
output_format = onlinejudge_template.analyzer.simple_patterns.guess_format_with_pattern_matching(instances=output_samples)
if output_format is None:
output_format = onlinejudge_template.analyzer.minimum_tree.construct_minimum_output_format_tree(instances=output_samples)
except AnalyzerError as e:
logger.info('failed to analyze the output format from the sample cases: %s', e)
if output_format is None:
logger.info('failed to analyze the output format: all analyzers failed')
# list the variables for output
output_variables: Optional[Dict[VarName, VarDecl]] = None
try:
if resources.output_format_string is None and topcoder_class_definition is not None:
output_variables = onlinejudge_template.analyzer.topcoder.convert_topcoder_class_definition_to_output_variables(topcoder_class_definition)
elif output_format is not None:
output_variables = onlinejudge_template.analyzer.variables.list_declared_variables(output_format)
if output_format is not None and output_variables is not None and resources.sample_cases:
output_samples = [case.output.decode() for case in resources.sample_cases]
output_types = onlinejudge_template.analyzer.typing.infer_types_from_instances(output_format, variables=output_variables, instances=output_samples)
output_variables = onlinejudge_template.analyzer.typing.update_variables_with_types(variables=output_variables, types=output_types)
except AnalyzerError as e:
logger.info('failed to list variables in the output format: %s', e)
# list constants
constants: Dict[VarName, ConstantDecl] = {}
try:
if resources.html is not None or resources.sample_cases:
constants.update(onlinejudge_template.analyzer.constants.list_constants(html=resources.html, sample_cases=resources.sample_cases))
except AnalyzerError as e:
logger.exception('failed to list used constants: %s', e)
# simplify the output format
output_type: Optional[OutputType] = None
try:
if output_format is not None and output_variables is not None:
output_type = onlinejudge_template.analyzer.output_types.analyze_output_type(output_format=output_format, output_variables=output_variables, constants=constants)
except AnalyzerError as e:
logger.info('failed to analyze the type of the output format: %s', e)
return AnalyzerResult(
resources=resources,
input_format=input_format,
output_format=output_format,
input_variables=input_variables,
output_variables=output_variables,
constants=constants,
output_type=output_type,
topcoder_class_definition=topcoder_class_definition,
)
[docs]def get_empty_analyzer_result(resources: AnalyzerResources) -> AnalyzerResult:
return AnalyzerResult(
resources=resources,
input_format=None,
output_format=None,
input_variables=None,
output_variables=None,
constants={},
output_type=None,
topcoder_class_definition=None,
)