diff --git a/.travis.yml b/.travis.yml index 0a993886..75beb77a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,10 +8,12 @@ python: before_install: - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y # for C++14 - sudo wget https://netcologne.dl.sourceforge.net/project/d-apt/files/d-apt.list -O /etc/apt/sources.list.d/d-apt.list # for D-lang, see https://d-apt.sourceforge.io/ + - sudo add-apt-repository ppa:longsleep/golang-backports -y # for Go, see https://github.com/golang/go/wiki/Ubuntu + - sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6 - sudo apt-get update --allow-insecure-repositories - sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring - sudo apt-get update - - sudo apt-get install rustc g++-4.9 openjdk-8-jdk nim dmd-compiler mono-complete + - sudo apt-get install rustc g++-4.9 openjdk-8-jdk nim dmd-compiler mono-complete golang-go - sudo ln -f -s /usr/bin/g++-4.9 /usr/bin/g++ install: diff --git a/atcodertools/client/atcoder.py b/atcodertools/client/atcoder.py index 043c07ca..b868a8e5 100644 --- a/atcodertools/client/atcoder.py +++ b/atcodertools/client/atcoder.py @@ -104,7 +104,7 @@ def download_problem_list(self, contest: Contest) -> List[Problem]: resp = self._request(contest.get_problem_list_url()) soup = BeautifulSoup(resp.text, "html.parser") res = [] - for tag in soup.select('.linkwrapper')[0::2]: + for tag in soup.select('.table a')[0::2]: alphabet = tag.text problem_id = tag.get("href").split("/")[-1] res.append(Problem(contest, alphabet, problem_id)) diff --git a/atcodertools/codegen/code_generators/go.py b/atcodertools/codegen/code_generators/go.py new file mode 100644 index 00000000..178e94cd --- /dev/null +++ b/atcodertools/codegen/code_generators/go.py @@ -0,0 +1,215 @@ +from typing import Dict, Any, Optional + +from atcodertools.codegen.code_style_config import CodeStyleConfig +from atcodertools.codegen.models.code_gen_args import CodeGenArgs +from atcodertools.codegen.template_engine import render +from atcodertools.fmtprediction.models.format import Pattern, SingularPattern, ParallelPattern, TwoDimensionalPattern, \ + Format +from atcodertools.fmtprediction.models.type import Type +from atcodertools.fmtprediction.models.variable import Variable + + +def _make_loop_header(loop_var: str, length: str): + return "for {loop_var} := 0; {loop_var} < {length}; {loop_var}++ {{".format( + loop_var=loop_var, + length=length + ) + + +def _loop_header(var: Variable, for_second_index: bool): + if for_second_index: + index = var.second_index + loop_var = "j" + else: + index = var.first_index + loop_var = "i" + return "for {loop_var} := 0; {loop_var} < {length}; {loop_var}++ {{".format( + loop_var=loop_var, + length=index.get_length() + ) + + +class GoCodeGenerator: + + def __init__(self, + format_: Optional[Format[Variable]], + config: CodeStyleConfig): + self._format = format_ + self._config = config + + def generate_parameters(self) -> Dict[str, Any]: + if self._format is None: + return dict(prediction_success=False) + + return dict(formal_arguments=self._formal_arguments(), + actual_arguments=self._actual_arguments(), + input_part=self._input_part(), + prediction_success=True) + + def _input_part(self): + lines = [] + for pattern in self._format.sequence: + lines += self._render_pattern(pattern) + return "\n{indent}".format(indent=self._indent(1)).join(lines) + + def _convert_type(self, type_: Type) -> str: + if type_ == Type.float: + return "float64" + elif type_ == Type.int: + return "int" + elif type_ == Type.str: + return "string" + else: + raise NotImplementedError + + def _get_declaration_type(self, var: Variable): + ctype = self._convert_type(var.type) + for _ in range(var.dim_num()): + ctype = '[]{}'.format(ctype) + return ctype + + def _actual_arguments(self) -> str: + """ + :return the string form of actual arguments e.g. "N, K, a" + """ + return ", ".join([v.name for v in self._format.all_vars()]) + + def _formal_arguments(self): + """ + :return the string form of formal arguments e.g. "N int, K int, a []int" + """ + return ", ".join([ + "{name} {decl_type}".format( + decl_type=self._get_declaration_type(v), + name=v.name) + for v in self._format.all_vars() + ]) + + def _generate_declaration(self, var: Variable): + """ + :return: Create declaration part as string[] E.g. array[1..n] -> ["array := make([]int, n)"] + array[1..n][1..m] -> + [ + "array := make([][]int, n)", + "for i := 0; i < n; i++ {", + " array[i] = make([]int, m)", + "}", + ] + """ + if var.dim_num() == 0: + dims = [] + elif var.dim_num() == 1: + dims = [var.first_index.get_length()] + elif var.dim_num() == 2: + dims = [var.first_index.get_length(), + var.second_index.get_length()] + else: + raise NotImplementedError + + lines = [] + + if len(dims) == 0: + lines.append("var {name} {decl_type}".format(name=var.name, + decl_type=self._get_declaration_type(var))) + else: + lines.append("{name} := make({decl_type}, {dim})".format(name=var.name, + decl_type=self._get_declaration_type( + var), + dim=dims[0])) + + indexes = "" + loop_vars = list("ijk") + ctype = self._convert_type(var.type) + for i, dim in enumerate(dims[1::1]): + loop_var = loop_vars[i] + lines.append(_make_loop_header(loop_var, dims[i])) + indexes += "[{}]".format(loop_var) + brackets = "[]" * (len(dims) - i - 1) + lines.append( + "{indent}{name}{indexes} = make({brackets}{ctype}, {dim})".format(indent=self._indent(i + 1), + name=var.name, + indexes=indexes, + brackets=brackets, + ctype=ctype, + dim=dim + )) + + for i in reversed(range(len(dims) - 1)): + lines.append("{indent}}}".format(indent=self._indent(i))) + + return lines + + def _input_code_for_var(self, var: Variable): + lines = ["scanner.Scan()"] + name = self._get_var_name(var) + if var.type == Type.float: + lines.append( + '{name}, _ = strconv.ParseFloat(scanner.Text(), 64)'.format(name=name)) + elif var.type == Type.int: + lines.append( + 'temp{name}, _ := strconv.ParseInt(scanner.Text(), 10, 64)'.format(name=name)) + lines.append( + '{name} = int(temp{name})'.format(name=name)) + elif var.type == Type.str: + lines.append('{name} = scanner.Text()'.format(name=name)) + else: + raise NotImplementedError + return lines + + @staticmethod + def _get_var_name(var: Variable): + name = var.name + if var.dim_num() >= 1: + name += "[i]" + if var.dim_num() >= 2: + name += "[j]" + return name + + def _render_pattern(self, pattern: Pattern): + lines = [] + for var in pattern.all_vars(): + lines.extend(self._generate_declaration(var)) + + representative_var = pattern.all_vars()[0] + if isinstance(pattern, SingularPattern): + lines.extend(self._input_code_for_var(representative_var)) + elif isinstance(pattern, ParallelPattern): + lines.append(_loop_header(representative_var, False)) + for var in pattern.all_vars(): + for line in self._input_code_for_var(var): + lines.append("{indent}{line}".format( + indent=self._indent(1), line=line)) + lines.append("}") + elif isinstance(pattern, TwoDimensionalPattern): + lines.append(_loop_header(representative_var, False)) + lines.append( + "{indent}{line}".format(indent=self._indent(1), line=_loop_header(representative_var, True))) + for var in pattern.all_vars(): + for line in self._input_code_for_var(var): + lines.append("{indent}{line}".format( + indent=self._indent(2), line=line)) + lines.append("{indent}}}".format(indent=self._indent(1))) + lines.append("}") + else: + raise NotImplementedError + + return lines + + def _indent(self, depth): + return self._config.indent(depth) + + +class NoPredictionResultGiven(Exception): + pass + + +def main(args: CodeGenArgs) -> str: + code_parameters = GoCodeGenerator( + args.format, args.config).generate_parameters() + return render( + args.template, + mod=args.constants.mod, + yes_str=args.constants.yes_str, + no_str=args.constants.no_str, + **code_parameters + ) diff --git a/atcodertools/codegen/code_style_config.py b/atcodertools/codegen/code_style_config.py index 833c4996..85882fb6 100644 --- a/atcodertools/codegen/code_style_config.py +++ b/atcodertools/codegen/code_style_config.py @@ -20,7 +20,7 @@ class CodeStyleConfigInitError(Exception): class CodeStyleConfig: def __init__(self, - indent_type: str = INDENT_TYPE_SPACE, + indent_type: Optional[str] = None, indent_width: Optional[int] = None, code_generator_file: Optional[str] = None, template_file: Optional[str] = None, @@ -38,7 +38,7 @@ def __init__(self, raise CodeStyleConfigInitError( "language must be one of {}".format(ALL_LANGUAGE_NAMES)) - if indent_type not in [INDENT_TYPE_SPACE, INDENT_TYPE_TAB]: + if indent_type is not None and indent_type not in [INDENT_TYPE_SPACE, INDENT_TYPE_TAB]: raise CodeStyleConfigInitError( "indent_type must be 'space' or 'tab'") @@ -56,14 +56,22 @@ def __init__(self, template_file) ) - self.indent_type = indent_type + if indent_type is not None: + self.indent_type = indent_type + elif lang.default_code_style is not None and lang.default_code_style.indent_type is not None: + self.indent_type = lang.default_code_style.indent_type + else: + self.indent_type = INDENT_TYPE_SPACE if indent_width is not None: self.indent_width = indent_width elif lang.default_code_style is not None and lang.default_code_style.indent_width is not None: self.indent_width = lang.default_code_style.indent_width else: - self.indent_width = 4 + if self.indent_type == INDENT_TYPE_SPACE: + self.indent_width = 4 + else: + self.indent_width = 1 if code_generator_file is not None: try: diff --git a/atcodertools/common/language.py b/atcodertools/common/language.py index 22fe7a5f..edb25aa1 100644 --- a/atcodertools/common/language.py +++ b/atcodertools/common/language.py @@ -1,7 +1,8 @@ import re from typing import Pattern, Callable -from atcodertools.codegen.code_generators import cpp, java, rust, python, nim, d, cs +from atcodertools.codegen.code_generators import cpp, java, rust, python, nim, d, cs, go +from atcodertools.codegen.code_style_config import INDENT_TYPE_TAB from atcodertools.codegen.models.code_gen_args import CodeGenArgs from atcodertools.tools.templates import get_default_template_path import platform @@ -13,8 +14,10 @@ class LanguageNotFoundError(Exception): class CodeStyle: def __init__(self, + indent_type=None, indent_width=None ): + self.indent_type = indent_type self.indent_width = indent_width @@ -163,6 +166,19 @@ def from_name(cls, name: str): exec_filename="{filename}{exec_extension}" ) +GO = Language( + name="go", + display_name="Go", + extension="go", + submission_lang_pattern=re.compile(".*Go \\(1.*"), + default_code_generator=go.main, + default_template_path=get_default_template_path('go'), + default_code_style=CodeStyle(indent_type=INDENT_TYPE_TAB), + compile_command="go build -o {filename} {filename}.go", + test_command="{exec_filename}", + exec_filename="{filename}{exec_extension}" +) + -ALL_LANGUAGES = [CPP, JAVA, RUST, PYTHON, NIM, DLANG, CSHARP] +ALL_LANGUAGES = [CPP, JAVA, RUST, PYTHON, NIM, DLANG, CSHARP, GO] ALL_LANGUAGE_NAMES = [lang.name for lang in ALL_LANGUAGES] diff --git a/atcodertools/tools/templates/default_template.go b/atcodertools/tools/templates/default_template.go new file mode 100644 index 00000000..1c9aa9b2 --- /dev/null +++ b/atcodertools/tools/templates/default_template.go @@ -0,0 +1,41 @@ +package main +{% if prediction_success %} + +import ( + "bufio" + "os" + "strconv" +) +{% endif %} +{% if mod or yes_str or no_str %} + +{% endif %} +{% if mod %} +const MOD = {{mod}} +{% endif %} +{% if yes_str %} +const YES = "{{ yes_str }}" +{% endif %} +{% if no_str %} +const NO = "{{ no_str }}" +{% endif %} +{% if prediction_success %} + +func solve({{ formal_arguments }}) { + +} +{% endif %} + +func main() { + {% if prediction_success %} + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + {{ input_part }} + solve({{ actual_arguments }}) + {% else %} + // Failed to predict input format + {% endif %} +} diff --git a/tests/resources/test_codegen/template.go b/tests/resources/test_codegen/template.go new file mode 100644 index 00000000..d2058f99 --- /dev/null +++ b/tests/resources/test_codegen/template.go @@ -0,0 +1,21 @@ +package main + +import ( + "bufio" + "os" + "strconv" +) + +func solve(${formal_arguments}) { + +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + ${input_part} + solve(${actual_arguments}) +} diff --git a/tests/resources/test_codegen/template_jinja.go b/tests/resources/test_codegen/template_jinja.go new file mode 100644 index 00000000..1c9aa9b2 --- /dev/null +++ b/tests/resources/test_codegen/template_jinja.go @@ -0,0 +1,41 @@ +package main +{% if prediction_success %} + +import ( + "bufio" + "os" + "strconv" +) +{% endif %} +{% if mod or yes_str or no_str %} + +{% endif %} +{% if mod %} +const MOD = {{mod}} +{% endif %} +{% if yes_str %} +const YES = "{{ yes_str }}" +{% endif %} +{% if no_str %} +const NO = "{{ no_str }}" +{% endif %} +{% if prediction_success %} + +func solve({{ formal_arguments }}) { + +} +{% endif %} + +func main() { + {% if prediction_success %} + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + {{ input_part }} + solve({{ actual_arguments }}) + {% else %} + // Failed to predict input format + {% endif %} +} diff --git a/tests/resources/test_codegen/test_default_code_generators_and_templates/go/echo_template.go b/tests/resources/test_codegen/test_default_code_generators_and_templates/go/echo_template.go new file mode 100644 index 00000000..20f5d33a --- /dev/null +++ b/tests/resources/test_codegen/test_default_code_generators_and_templates/go/echo_template.go @@ -0,0 +1,81 @@ +package main +{% if prediction_success %} + +import ( + "bufio" + "fmt" + "log" + "os" + "strconv" +) +{% endif %} +{% if mod or yes_str or no_str %} + +{% endif %} +{% if mod %} +const MOD = {{mod}} +{% endif %} +{% if yes_str %} +const YES = "{{ yes_str }}" +{% endif %} +{% if no_str %} +const NO = "{{ no_str }}" +{% endif %} +{% if prediction_success %} + +func solve({{ formal_arguments }}) { + fmt.Printf("%d %d\n", N, M) + if int64(len(H)) != N-1 { + log.Fatal() + } + for i := int64(0); i < N-1; i++ { + if int64(len(H[i])) != M-2 { + log.Fatal() + } + for j := int64(0); j < M-2; j++ { + if j > 0 { + fmt.Printf(" %s", H[i][j]) + } else { + fmt.Printf("%s", H[i][j]) + } + } + fmt.Println() + } + + if int64(len(A)) != N-1 { + log.Fatal() + } + if int64(len(B)) != N-1 { + log.Fatal() + } + for i := int64(0); i < N-1; i++ { + fmt.Printf("%d %.1f\n", A[i], B[i]) + } + + fmt.Println(Q) + if int64(len(X)) != M+Q { + log.Fatal() + } + for i := int64(0); i < M+Q; i++ { + fmt.Println(X[i]) + } + + fmt.Println(YES) + fmt.Println(NO) + fmt.Println(MOD) +} +{% endif %} + +func main() { + {% if prediction_success %} + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + {{ input_part }} + solve({{ actual_arguments }}) + {% else %} + // Failed to predict input format + {% endif %} +} diff --git a/tests/resources/test_codegen/test_default_code_generators_and_templates/go/expected_default_generated_code.go b/tests/resources/test_codegen/test_default_code_generators_and_templates/go/expected_default_generated_code.go new file mode 100644 index 00000000..5de7d0bf --- /dev/null +++ b/tests/resources/test_codegen/test_default_code_generators_and_templates/go/expected_default_generated_code.go @@ -0,0 +1,56 @@ +package main + +import ( + "bufio" + "os" + "strconv" +) + +const MOD = 123 +const YES = "yes" +const NO = "NO" + +func solve(N int64, M int64, H [][]string, A []int64, B []float64, Q int64, X []int64) { + +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + var N int64 + scanner.Scan() + N, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var M int64 + scanner.Scan() + M, _ = strconv.ParseInt(scanner.Text(), 10, 64) + H := make([][]string, N-2+1) + for i := int64(0); i < N-2+1; i++ { + H[i] = make([]string, M-1-2+1) + } + for i := int64(0); i < N-2+1; i++ { + for j := int64(0); j < M-1-2+1; j++ { + scanner.Scan() + H[i][j] = scanner.Text() + } + } + A := make([]int64, N-2+1) + B := make([]float64, N-2+1) + for i := int64(0); i < N-2+1; i++ { + scanner.Scan() + A[i], _ = strconv.ParseInt(scanner.Text(), 10, 64) + scanner.Scan() + B[i], _ = strconv.ParseFloat(scanner.Text(), 64) + } + var Q int64 + scanner.Scan() + Q, _ = strconv.ParseInt(scanner.Text(), 10, 64) + X := make([]int64, M+Q) + for i := int64(0); i < M+Q; i++ { + scanner.Scan() + X[i], _ = strconv.ParseInt(scanner.Text(), 10, 64) + } + solve(N, M, H, A, B, Q, X) +} diff --git a/tests/resources/test_codegen/test_default_code_generators_and_templates/go/expected_echo_generated_code.go b/tests/resources/test_codegen/test_default_code_generators_and_templates/go/expected_echo_generated_code.go new file mode 100644 index 00000000..01fb6c30 --- /dev/null +++ b/tests/resources/test_codegen/test_default_code_generators_and_templates/go/expected_echo_generated_code.go @@ -0,0 +1,96 @@ +package main + +import ( + "bufio" + "fmt" + "log" + "os" + "strconv" +) + +const MOD = 123 +const YES = "yes" +const NO = "NO" + +func solve(N int64, M int64, H [][]string, A []int64, B []float64, Q int64, X []int64) { + fmt.Printf("%d %d\n", N, M) + if int64(len(H)) != N-1 { + log.Fatal() + } + for i := int64(0); i < N-1; i++ { + if int64(len(H[i])) != M-2 { + log.Fatal() + } + for j := int64(0); j < M-2; j++ { + if j > 0 { + fmt.Printf(" %s", H[i][j]) + } else { + fmt.Printf("%s", H[i][j]) + } + } + fmt.Println() + } + + if int64(len(A)) != N-1 { + log.Fatal() + } + if int64(len(B)) != N-1 { + log.Fatal() + } + for i := int64(0); i < N-1; i++ { + fmt.Printf("%d %.1f\n", A[i], B[i]) + } + + fmt.Println(Q) + if int64(len(X)) != M+Q { + log.Fatal() + } + for i := int64(0); i < M+Q; i++ { + fmt.Println(X[i]) + } + + fmt.Println(YES) + fmt.Println(NO) + fmt.Println(MOD) +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + var N int64 + scanner.Scan() + N, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var M int64 + scanner.Scan() + M, _ = strconv.ParseInt(scanner.Text(), 10, 64) + H := make([][]string, N-2+1) + for i := int64(0); i < N-2+1; i++ { + H[i] = make([]string, M-1-2+1) + } + for i := int64(0); i < N-2+1; i++ { + for j := int64(0); j < M-1-2+1; j++ { + scanner.Scan() + H[i][j] = scanner.Text() + } + } + A := make([]int64, N-2+1) + B := make([]float64, N-2+1) + for i := int64(0); i < N-2+1; i++ { + scanner.Scan() + A[i], _ = strconv.ParseInt(scanner.Text(), 10, 64) + scanner.Scan() + B[i], _ = strconv.ParseFloat(scanner.Text(), 64) + } + var Q int64 + scanner.Scan() + Q, _ = strconv.ParseInt(scanner.Text(), 10, 64) + X := make([]int64, M+Q) + for i := int64(0); i < M+Q; i++ { + scanner.Scan() + X[i], _ = strconv.ParseInt(scanner.Text(), 10, 64) + } + solve(N, M, H, A, B, Q, X) +} diff --git a/tests/resources/test_codegen/test_float_case/go/generated_code.txt b/tests/resources/test_codegen/test_float_case/go/generated_code.txt new file mode 100644 index 00000000..177d234b --- /dev/null +++ b/tests/resources/test_codegen/test_float_case/go/generated_code.txt @@ -0,0 +1,42 @@ +package main + +import ( + "bufio" + "os" + "strconv" +) + +func solve(L int64, N int64, M int64, K []float64, A []int64, S []float64) { + +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + var L int64 + scanner.Scan() + L, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var N int64 + scanner.Scan() + N, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var M int64 + scanner.Scan() + M, _ = strconv.ParseInt(scanner.Text(), 10, 64) + K := make([]float64, L) + for i := int64(0); i < L; i++ { + scanner.Scan() + K[i], _ = strconv.ParseFloat(scanner.Text(), 64) + } + A := make([]int64, N) + S := make([]float64, N) + for i := int64(0); i < N; i++ { + scanner.Scan() + A[i], _ = strconv.ParseInt(scanner.Text(), 10, 64) + scanner.Scan() + S[i], _ = strconv.ParseFloat(scanner.Text(), 64) + } + solve(L, N, M, K, A, S) +} diff --git a/tests/resources/test_codegen/test_long_case/go/generated_code.txt b/tests/resources/test_codegen/test_long_case/go/generated_code.txt new file mode 100644 index 00000000..751ddd0b --- /dev/null +++ b/tests/resources/test_codegen/test_long_case/go/generated_code.txt @@ -0,0 +1,57 @@ +package main + +import ( + "bufio" + "os" + "strconv" +) + +func solve(H int64, W int64, K int64, sr int64, sc int64, s []string, N int64, fr []int64, fc []int64, F []int64, D []int64) { + +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + var H int64 + scanner.Scan() + H, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var W int64 + scanner.Scan() + W, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var K int64 + scanner.Scan() + K, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var sr int64 + scanner.Scan() + sr, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var sc int64 + scanner.Scan() + sc, _ = strconv.ParseInt(scanner.Text(), 10, 64) + s := make([]string, H) + for i := int64(0); i < H; i++ { + scanner.Scan() + s[i] = scanner.Text() + } + var N int64 + scanner.Scan() + N, _ = strconv.ParseInt(scanner.Text(), 10, 64) + fr := make([]int64, N) + fc := make([]int64, N) + F := make([]int64, N) + D := make([]int64, N) + for i := int64(0); i < N; i++ { + scanner.Scan() + fr[i], _ = strconv.ParseInt(scanner.Text(), 10, 64) + scanner.Scan() + fc[i], _ = strconv.ParseInt(scanner.Text(), 10, 64) + scanner.Scan() + F[i], _ = strconv.ParseInt(scanner.Text(), 10, 64) + scanner.Scan() + D[i], _ = strconv.ParseInt(scanner.Text(), 10, 64) + } + solve(H, W, K, sr, sc, s, N, fr, fc, F, D) +} diff --git a/tests/resources/test_codegen/test_mod_case/go/generated_code.txt b/tests/resources/test_codegen/test_mod_case/go/generated_code.txt new file mode 100644 index 00000000..62814586 --- /dev/null +++ b/tests/resources/test_codegen/test_mod_case/go/generated_code.txt @@ -0,0 +1,28 @@ +package main + +import ( + "bufio" + "os" + "strconv" +) + +const MOD = 998244353 + +func solve(A string, B string) { + +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + var A string + scanner.Scan() + A = scanner.Text() + var B string + scanner.Scan() + B = scanner.Text() + solve(A, B) +} diff --git a/tests/resources/test_codegen/test_two_dimensional_case/go/generated_code.txt b/tests/resources/test_codegen/test_two_dimensional_case/go/generated_code.txt new file mode 100644 index 00000000..ad5c75e7 --- /dev/null +++ b/tests/resources/test_codegen/test_two_dimensional_case/go/generated_code.txt @@ -0,0 +1,46 @@ +package main + +import ( + "bufio" + "os" + "strconv" +) + +func solve(H int64, W int64, c [][]int64, A [][]int64) { + +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + var H int64 + scanner.Scan() + H, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var W int64 + scanner.Scan() + W, _ = strconv.ParseInt(scanner.Text(), 10, 64) + c := make([][]int64, 9-0+1) + for i := int64(0); i < 9-0+1; i++ { + c[i] = make([]int64, 9-0+1) + } + for i := int64(0); i < 9-0+1; i++ { + for j := int64(0); j < 9-0+1; j++ { + scanner.Scan() + c[i][j], _ = strconv.ParseInt(scanner.Text(), 10, 64) + } + } + A := make([][]int64, H) + for i := int64(0); i < H; i++ { + A[i] = make([]int64, W) + } + for i := int64(0); i < H; i++ { + for j := int64(0); j < W; j++ { + scanner.Scan() + A[i][j], _ = strconv.ParseInt(scanner.Text(), 10, 64) + } + } + solve(H, W, c, A) +} diff --git a/tests/resources/test_codegen/test_yes_no_case/go/generated_code.txt b/tests/resources/test_codegen/test_yes_no_case/go/generated_code.txt new file mode 100644 index 00000000..475a0abe --- /dev/null +++ b/tests/resources/test_codegen/test_yes_no_case/go/generated_code.txt @@ -0,0 +1,35 @@ +package main + +import ( + "bufio" + "os" + "strconv" +) + +const YES = "YES" +const NO = "NO" + +func solve(N int64, M int64, A int64, B int64) { + +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + const initialBufSize = 4096 + const maxBufSize = 1000000 + scanner.Buffer(make([]byte, initialBufSize), maxBufSize) + scanner.Split(bufio.ScanWords) + var N int64 + scanner.Scan() + N, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var M int64 + scanner.Scan() + M, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var A int64 + scanner.Scan() + A, _ = strconv.ParseInt(scanner.Text(), 10, 64) + var B int64 + scanner.Scan() + B, _ = strconv.ParseInt(scanner.Text(), 10, 64) + solve(N, M, A, B) +} diff --git a/tests/resources/test_tester/test_compiler_and_tester/main.go b/tests/resources/test_tester/test_compiler_and_tester/main.go new file mode 100644 index 00000000..5b2857c5 --- /dev/null +++ b/tests/resources/test_tester/test_compiler_and_tester/main.go @@ -0,0 +1,13 @@ +package main + +import "fmt" + +func main() { + var A, B, C int + fmt.Scan(&A, &B, &C) + if A+B >= C { + fmt.Println("Yes") + } else { + fmt.Println("No") + } +} diff --git a/tests/test_codegen.py b/tests/test_codegen.py index aa831b83..2ae8d81d 100644 --- a/tests/test_codegen.py +++ b/tests/test_codegen.py @@ -7,14 +7,14 @@ from atcodertools.client.models.problem_content import ProblemContent from atcodertools.client.models.sample import Sample -from atcodertools.common.language import ALL_LANGUAGES, Language, CPP, JAVA, RUST, PYTHON, NIM, DLANG, CSHARP +from atcodertools.common.language import ALL_LANGUAGES, Language, CPP, JAVA, RUST, PYTHON, NIM, DLANG, CSHARP, GO from atcodertools.executils.run_command import run_command from atcodertools.executils.run_program import run_program from atcodertools.fileutils.create_contest_file import create_code from atcodertools.fileutils.load_text_file import load_text_file from atcodertools.fmtprediction.predict_format import predict_format -from atcodertools.codegen.code_generators import cpp, java, rust, python, nim, d, cs +from atcodertools.codegen.code_generators import cpp, java, rust, python, nim, d, cs, go from atcodertools.codegen.code_style_config import CodeStyleConfig from atcodertools.codegen.models.code_gen_args import CodeGenArgs from atcodertools.codegen.template_engine import render @@ -78,6 +78,10 @@ def setUp(self): CSHARP: { "old": "template.cs", "jinja": "template_jinja.cs", + }, + GO: { + "old": "template.go", + "jinja": "template_jinja.go", } } self.lang_to_code_generator_func = { @@ -88,6 +92,7 @@ def setUp(self): NIM: nim.main, DLANG: d.main, CSHARP: cs.main, + GO: go.main, } self.maxDiff = None @@ -189,6 +194,8 @@ def _compile_command(self, lang: Language, code_file: str): return "dmd {} -of=main".format(code_file) elif lang == CSHARP: return "mcs {}".format(code_file) + elif lang == GO: + return "go build -o main {}".format(code_file) else: raise NotImplementedError() @@ -207,6 +214,8 @@ def _exec_file_and_args(self, lang: Language) -> Tuple[str, List[str]]: return "./main", [] elif lang == CSHARP: return "mono", ["main.exe"] + elif lang == GO: + return "./main", [] else: raise NotImplementedError() @@ -225,6 +234,8 @@ def _clean_up(self, lang: Language): os.remove(os.path.join(self.temp_dir, "main")) elif lang == CSHARP: os.remove(os.path.join(self.temp_dir, "main.exe")) + elif lang == GO: + os.remove(os.path.join(self.temp_dir, "main")) else: raise NotImplementedError()