Skip to content

Commit 7826e9b

Browse files
penpenpngkyuridenamida
authored andcommitted
D言語用のジェネレータとテンプレートを追加 (kyuridenamida#145)
* D言語用のジェネレータとテンプレートを追加 * windows での test 時に実行ファイルを誤検出する問題の修正 * クラス名を修正 * テストを追加 * pep8に従ってスタイルを修正 * python3.5以下で動くように修正 * windows環境下での is_executable_file のテストを追加 * 不要な例外クラスを削除 * pep8 に怒られたので修正……
1 parent 163237c commit 7826e9b

File tree

17 files changed

+688
-7
lines changed

17 files changed

+688
-7
lines changed

.travis.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ python:
77

88
before_install:
99
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y # for C++14
10+
- 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/
11+
- sudo apt-get update --allow-insecure-repositories
12+
- sudo apt-get -y --allow-unauthenticated install --reinstall d-apt-keyring
1013
- sudo apt-get update
11-
- sudo apt-get install rustc g++-4.9 openjdk-8-jdk nim
14+
- sudo apt-get install rustc g++-4.9 openjdk-8-jdk nim dmd-compiler
1215
- sudo ln -f -s /usr/bin/g++-4.9 /usr/bin/g++
1316

1417
install:
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
from typing import Dict, Any, Optional
2+
3+
from atcodertools.codegen.code_style_config import CodeStyleConfig
4+
from atcodertools.codegen.models.code_gen_args import CodeGenArgs
5+
from atcodertools.codegen.template_engine import render
6+
from atcodertools.fmtprediction.models.format import (
7+
Pattern,
8+
SingularPattern,
9+
ParallelPattern,
10+
TwoDimensionalPattern,
11+
Format)
12+
from atcodertools.fmtprediction.models.type import Type
13+
from atcodertools.fmtprediction.models.variable import Variable
14+
15+
16+
def _loop_header(var: Variable, for_second_index: bool):
17+
if for_second_index:
18+
index = var.second_index
19+
loop_var = "j"
20+
else:
21+
index = var.first_index
22+
loop_var = "i"
23+
24+
return "foreach ({loop_var}; 0 .. cast(size_t) ({length})) {{".format(
25+
loop_var=loop_var,
26+
length=index.get_length())
27+
28+
29+
class DlangCodeGenerator:
30+
def __init__(self,
31+
format_: Optional[Format[Variable]],
32+
config: CodeStyleConfig):
33+
self._format = format_
34+
self._config = config
35+
36+
def generate_parameters(self) -> Dict[str, Any]:
37+
if self._format is None:
38+
return dict(prediction_success=False)
39+
40+
return dict(
41+
formal_arguments=self._formal_arguments(),
42+
actual_arguments=self._actual_arguments(),
43+
input_part=self._input_part(),
44+
prediction_success=True)
45+
46+
def _formal_arguments(self):
47+
"""
48+
:return the string form of formal arguments e.g. "int N, int K, int[] a"
49+
"""
50+
return ", ".join([
51+
"{decl_type} {name}".format(
52+
decl_type=self._get_declaration_type(v),
53+
name=v.name)
54+
for v in self._format.all_vars()])
55+
56+
def _actual_arguments(self) -> str:
57+
"""
58+
:return the string form of actual arguments e.g. "N, K, a"
59+
"""
60+
return ", ".join([v.name for v in self._format.all_vars()])
61+
62+
def _input_part(self):
63+
lines = []
64+
for pattern in self._format.sequence:
65+
lines.extend(self._render_pattern(pattern))
66+
lines.append("")
67+
68+
code = "auto input = stdin.byLine.map!split.joiner;\n\n"
69+
for line in lines:
70+
if line == "":
71+
code += "\n"
72+
else:
73+
code += "{indent}{line}\n".format(
74+
indent=self._indent(1),
75+
line=line)
76+
77+
return code[:-1]
78+
79+
def _render_pattern(self, pattern: Pattern):
80+
lines = []
81+
for var in pattern.all_vars():
82+
lines.append(self._generate_declaration(var))
83+
84+
representative_var = pattern.all_vars()[0]
85+
if isinstance(pattern, SingularPattern):
86+
lines.extend(self._assignment_code(representative_var))
87+
elif isinstance(pattern, ParallelPattern):
88+
lines.append(_loop_header(representative_var, False))
89+
for var in pattern.all_vars():
90+
lines.extend(self._assignment_code(var, indent_level=1))
91+
lines.append("}")
92+
elif isinstance(pattern, TwoDimensionalPattern):
93+
lines.append(_loop_header(representative_var, False))
94+
lines.append(
95+
"{indent}{line}".format(
96+
indent=self._indent(1),
97+
line=_loop_header(representative_var, True)))
98+
for var in pattern.all_vars():
99+
lines.extend(self._assignment_code(var, indent_level=2))
100+
lines.append("{indent}}}".format(indent=self._indent(1)))
101+
lines.append("}")
102+
else:
103+
raise NotImplementedError
104+
105+
return lines
106+
107+
def _generate_declaration(self, var: Variable):
108+
"""
109+
:return: Create declaration part e.g. array[1..n] -> int[] array = new int[](n-1+1);
110+
"""
111+
if var.dim_num() == 0:
112+
dims = []
113+
elif var.dim_num() == 1:
114+
dims = [var.first_index.get_length()]
115+
elif var.dim_num() == 2:
116+
dims = [var.first_index.get_length(),
117+
var.second_index.get_length()]
118+
else:
119+
raise NotImplementedError
120+
121+
decl_type = self._get_declaration_type(var)
122+
line = "{decl_type} {name}".format(
123+
name=var.name,
124+
decl_type=decl_type)
125+
126+
if len(dims) > 0:
127+
ctor_args = map(lambda d: "cast(size_t) ({})".format(d), dims)
128+
line += ' = new {}({})'.format(decl_type, ", ".join(ctor_args))
129+
130+
line += ";"
131+
132+
return line
133+
134+
def _assignment_code(self, var: Variable, indent_level: int = 0) -> str:
135+
line1 = "{indent}{varname} = input.front.to!{vartype};"
136+
line2 = "{indent}input.popFront;"
137+
indent = self._indent(indent_level)
138+
139+
return [
140+
line1.format(
141+
indent=indent,
142+
varname=self._get_var_name(var),
143+
vartype=self._get_var_basetype(var)),
144+
line2.format(
145+
indent=indent)]
146+
147+
@staticmethod
148+
def _get_var_name(var: Variable):
149+
name = var.name
150+
if var.dim_num() >= 1:
151+
name += "[i]"
152+
if var.dim_num() >= 2:
153+
name += "[j]"
154+
return name
155+
156+
@staticmethod
157+
def _get_var_basetype(var: Variable) -> str:
158+
type_ = var.type
159+
if type_ == Type.float:
160+
return "double"
161+
elif type_ == Type.int:
162+
return "long"
163+
elif type_ == Type.str:
164+
return "string"
165+
else:
166+
raise NotImplementedError
167+
168+
@classmethod
169+
def _get_declaration_type(cls, var: Variable):
170+
ctype = cls._get_var_basetype(var)
171+
for _ in range(var.dim_num()):
172+
ctype += "[]"
173+
return ctype
174+
175+
def _indent(self, depth):
176+
return self._config.indent(depth)
177+
178+
179+
def main(args: CodeGenArgs) -> str:
180+
code_parameters = DlangCodeGenerator(
181+
args.format, args.config).generate_parameters()
182+
return render(
183+
args.template,
184+
mod=args.constants.mod,
185+
yes_str=args.constants.yes_str,
186+
no_str=args.constants.no_str,
187+
**code_parameters)

atcodertools/common/language.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import re
22
from typing import Pattern, Callable
33

4-
from atcodertools.codegen.code_generators import cpp, java, rust, python, nim
4+
from atcodertools.codegen.code_generators import cpp, java, rust, python, nim, d
55
from atcodertools.codegen.models.code_gen_args import CodeGenArgs
66
from atcodertools.tools.templates import get_default_template_path
77

@@ -76,6 +76,15 @@ def from_name(cls, name: str):
7676
default_template_path=get_default_template_path('py'),
7777
)
7878

79+
DLANG = Language(
80+
name="d",
81+
display_name="D",
82+
extension="d",
83+
submission_lang_pattern=re.compile(".*DMD64.*"),
84+
default_code_generator=d.main,
85+
default_template_path=get_default_template_path('d'),
86+
)
87+
7988
NIM = Language(
8089
name="nim",
8190
display_name="NIM",
@@ -85,5 +94,5 @@ def from_name(cls, name: str):
8594
default_template_path=get_default_template_path('nim'),
8695
)
8796

88-
ALL_LANGUAGES = [CPP, JAVA, RUST, PYTHON, NIM]
97+
ALL_LANGUAGES = [CPP, JAVA, RUST, PYTHON, NIM, DLANG]
8998
ALL_LANGUAGE_NAMES = [lang.display_name for lang in ALL_LANGUAGES]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{% if prediction_success %}
2+
import std.algorithm;
3+
import std.conv;
4+
import std.stdio;
5+
import std.string;
6+
{% endif %}
7+
{% if mod or yes_str or no_str %}
8+
9+
{% endif %}
10+
{% if mod %}
11+
immutable long MOD = {{ mod }};
12+
{% endif %}
13+
{% if yes_str %}
14+
immutable string YES = "{{ yes_str }}";
15+
{% endif %}
16+
{% if no_str %}
17+
immutable string NO = "{{ no_str }}";
18+
{% endif %}
19+
{% if prediction_success %}
20+
21+
void solve({{ formal_arguments }}){
22+
23+
}
24+
25+
{% endif %}
26+
// Generated by {{ atcodertools.version }} {{ atcodertools.url }} (tips: You use the default template now. You can remove this line by using your custom template)
27+
int main(){
28+
{% if prediction_success %}
29+
{{ input_part }}
30+
solve({{ actual_arguments }});
31+
{% else %}
32+
// Failed to predict input format
33+
{% endif %}
34+
return 0;
35+
}

atcodertools/tools/tester.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
import argparse
33
import glob
44
import os
5+
import platform
6+
import re
57
import sys
68
from pathlib import Path
79
from typing import List, Tuple
@@ -32,8 +34,13 @@ def __eq__(self, other):
3234

3335

3436
def is_executable_file(file_name):
35-
return os.access(file_name, os.X_OK) and Path(file_name).is_file() \
36-
and file_name.find(".cpp") == -1 and not file_name.endswith(".txt") # cppやtxtを省くのは一応の Cygwin 対策
37+
if platform.system() == "Windows":
38+
return any(
39+
re.match(r"^.*\{ext}$".format(ext=ext), file_name, re.IGNORECASE)
40+
for ext in os.environ.get("pathext", default="").split(";"))
41+
else:
42+
return os.access(file_name, os.X_OK) and Path(file_name).is_file() \
43+
and file_name.find(".cpp") == -1 and not file_name.endswith(".txt") # cppやtxtを省くのは一応の Cygwin 対策
3744

3845

3946
def infer_exec_file(filenames):
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import std.algorithm;
2+
import std.conv;
3+
import std.stdio;
4+
import std.string;
5+
6+
void solve(${formal_arguments}){
7+
8+
}
9+
10+
int main(){
11+
${input_part}
12+
solve(${actual_arguments});
13+
return 0;
14+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{% if prediction_success %}
2+
import std.algorithm;
3+
import std.conv;
4+
import std.stdio;
5+
import std.string;
6+
{% endif %}
7+
{% if mod or yes_str or no_str %}
8+
9+
{% endif %}
10+
{% if mod %}
11+
immutable long MOD = {{ mod }};
12+
{% endif %}
13+
{% if yes_str %}
14+
immutable string YES = "{{ yes_str }}";
15+
{% endif %}
16+
{% if no_str %}
17+
immutable string NO = "{{ no_str }}";
18+
{% endif %}
19+
{% if prediction_success %}
20+
21+
void solve({{ formal_arguments }}){
22+
23+
}
24+
25+
{% endif %}
26+
int main(){
27+
{% if prediction_success %}
28+
{{ input_part }}
29+
solve({{ actual_arguments }});
30+
{% else %}
31+
{% endif %}
32+
return 0;
33+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import std.algorithm;
2+
import std.conv;
3+
import std.stdio;
4+
import std.string;
5+
{% if mod or yes_str or no_str %}
6+
7+
{% endif %}
8+
{% if mod %}
9+
immutable long MOD = {{ mod }};
10+
{% endif %}
11+
{% if yes_str %}
12+
immutable string YES = "{{ yes_str }}";
13+
{% endif %}
14+
{% if no_str %}
15+
immutable string NO = "{{ no_str }}";
16+
{% endif %}
17+
{% if prediction_success %}
18+
19+
void solve({{ formal_arguments }}){
20+
writeln(N.to!string ~ " " ~ M.to!string);
21+
assert(H.length == cast(size_t) (N - 1));
22+
foreach (i; 0 .. cast(size_t) (N - 1)) {
23+
assert(H[i].length == M - 2);
24+
writeln(H[i].join(" "));
25+
}
26+
assert(A.length == cast(size_t) (N - 1));
27+
assert(B.length == cast(size_t) (N - 1));
28+
foreach (i; 0 .. cast(size_t) (N - 1)) {
29+
writeln(A[i].to!string ~ " " ~ B[i].to!string);
30+
}
31+
writeln(Q);
32+
assert(X.length == cast(size_t) (M + Q));
33+
foreach (i; 0 .. cast(size_t) (M + Q)) {
34+
writeln(X[i]);
35+
}
36+
37+
writeln(YES);
38+
writeln(NO);
39+
writeln(MOD);
40+
}
41+
42+
{% endif %}
43+
int main(){
44+
{% if prediction_success %}
45+
{{ input_part }}
46+
solve({{ actual_arguments }});
47+
{% endif %}
48+
return 0;
49+
}

0 commit comments

Comments
 (0)