Skip to content

Commit 6867dc3

Browse files
authored
Add Swift Support (#211)
* Add Swift Support * Update Swift template * Fix line length violation * Fix test
1 parent 128055c commit 6867dc3

File tree

14 files changed

+658
-4
lines changed

14 files changed

+658
-4
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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 Pattern, SingularPattern, ParallelPattern, TwoDimensionalPattern, \
7+
Format
8+
from atcodertools.fmtprediction.models.type import Type
9+
from atcodertools.fmtprediction.models.variable import Variable
10+
from atcodertools.fmtprediction.models.index import Index
11+
12+
13+
def _loop_header(var: Variable, index: Index, omit_name: bool):
14+
loop_var = '_' if omit_name else 'i'
15+
return 'for {loop_var} in 0..<{length} {{'.format(
16+
loop_var=loop_var,
17+
length=index.get_length()
18+
)
19+
20+
21+
class SwiftCodeGenerator:
22+
23+
def __init__(self,
24+
format_: Optional[Format[Variable]],
25+
config: CodeStyleConfig):
26+
self._format = format_
27+
self._config = config
28+
29+
def generate_parameters(self) -> Dict[str, Any]:
30+
if self._format is None:
31+
return dict(prediction_success=False)
32+
33+
return dict(formal_arguments=self._formal_arguments(),
34+
actual_arguments=self._actual_arguments(),
35+
input_part=self._input_part(),
36+
prediction_success=True)
37+
38+
def _input_part(self):
39+
lines = []
40+
for pattern in self._format.sequence:
41+
lines += self._render_pattern(pattern)
42+
return "\n{indent}".format(indent=self._indent(1)).join(lines)
43+
44+
def _convert_type(self, type_: Type) -> str:
45+
if type_ == Type.float:
46+
return "Double"
47+
elif type_ == Type.int:
48+
return "Int"
49+
elif type_ == Type.str:
50+
return "String"
51+
else:
52+
raise NotImplementedError
53+
54+
def _get_declaration_type(self, var: Variable):
55+
ctype = self._convert_type(var.type)
56+
for _ in range(var.dim_num()):
57+
ctype = '[{}]'.format(ctype)
58+
return ctype
59+
60+
def _actual_arguments(self) -> str:
61+
"""
62+
:return the string form of actual arguments e.g. "N, K, a"
63+
"""
64+
return ", ".join([v.name for v in self._format.all_vars()])
65+
66+
def _formal_arguments(self):
67+
"""
68+
:return the string form of formal arguments e.g. "_ N:Int, _ K:Int, _ a:[Int]"
69+
"""
70+
return ", ".join([
71+
"_ {name}:{decl_type}".format(
72+
decl_type=self._get_declaration_type(v),
73+
name=v.name)
74+
for v in self._format.all_vars()
75+
])
76+
77+
def _generate_declaration(self, var: Variable):
78+
"""
79+
:return: Create declaration part E.g. array[1..n] -> var array = [Int]()
80+
"""
81+
return 'var {name} = {decl_type}()'.format(name=var.name, decl_type=self._get_declaration_type(var))
82+
83+
def _input_code_for_var(self, var: Variable) -> str:
84+
name = self._get_var_name(var)
85+
ctype = self._convert_type(var.type)
86+
getnext = 'read{ctype}()'.format(ctype=ctype)
87+
if var.dim_num() == 0:
88+
return 'let {name} = {getnext}'.format(name=name, getnext=getnext)
89+
else:
90+
return '{name}.append({getnext})'.format(name=name, getnext=getnext)
91+
92+
@staticmethod
93+
def _get_var_name(var: Variable):
94+
name = var.name
95+
if var.dim_num() >= 2:
96+
name += "[i]"
97+
return name
98+
99+
def _two_dimension_header(self, var: Variable) -> str:
100+
name = var.name
101+
ctype = self._convert_type(var.type)
102+
return '{name}.append([{ctype}]())'.format(name=name, ctype=ctype)
103+
104+
def _render_pattern(self, pattern: Pattern):
105+
lines = []
106+
107+
if not isinstance(pattern, SingularPattern):
108+
for var in pattern.all_vars():
109+
lines.append(self._generate_declaration(var))
110+
111+
representative_var = pattern.all_vars()[0]
112+
if isinstance(pattern, SingularPattern):
113+
lines.append(self._input_code_for_var(representative_var))
114+
elif isinstance(pattern, ParallelPattern):
115+
lines.append(_loop_header(representative_var,
116+
representative_var.first_index, True))
117+
for var in pattern.all_vars():
118+
lines.append("{indent}{line}".format(indent=self._indent(1),
119+
line=self._input_code_for_var(var)))
120+
lines.append("}")
121+
elif isinstance(pattern, TwoDimensionalPattern):
122+
lines.append(_loop_header(representative_var,
123+
representative_var.first_index, False))
124+
lines.append("{indent}{line}".format(indent=self._indent(1),
125+
line=self._two_dimension_header(representative_var)))
126+
lines.append("{indent}{line}".format(indent=self._indent(1),
127+
line=_loop_header(representative_var, representative_var.second_index, True)))
128+
for var in pattern.all_vars():
129+
lines.append("{indent}{line}".format(indent=self._indent(2),
130+
line=self._input_code_for_var(var)))
131+
lines.append("{indent}}}".format(indent=self._indent(1)))
132+
lines.append("}")
133+
else:
134+
raise NotImplementedError
135+
136+
return lines
137+
138+
def _indent(self, depth):
139+
return self._config.indent(depth)
140+
141+
142+
class NoPredictionResultGiven(Exception):
143+
pass
144+
145+
146+
def main(args: CodeGenArgs) -> str:
147+
code_parameters = SwiftCodeGenerator(
148+
args.format, args.config).generate_parameters()
149+
return render(
150+
args.template,
151+
mod=args.constants.mod,
152+
yes_str=args.constants.yes_str,
153+
no_str=args.constants.no_str,
154+
**code_parameters
155+
)

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, d, cs
4+
from atcodertools.codegen.code_generators import cpp, java, rust, python, nim, d, cs, swift
55
from atcodertools.codegen.models.code_gen_args import CodeGenArgs
66
from atcodertools.tools.templates import get_default_template_path
77

@@ -113,6 +113,15 @@ def from_name(cls, name: str):
113113
default_template_path=get_default_template_path('cs'),
114114
)
115115

116+
SWIFT = Language(
117+
name="swift",
118+
display_name="Swift",
119+
extension="swift",
120+
submission_lang_pattern=re.compile("^Swift"),
121+
default_code_generator=swift.main,
122+
default_template_path=get_default_template_path('swift'),
123+
)
124+
116125

117-
ALL_LANGUAGES = [CPP, JAVA, RUST, PYTHON, NIM, DLANG, CSHARP]
126+
ALL_LANGUAGES = [CPP, JAVA, RUST, PYTHON, NIM, DLANG, CSHARP, SWIFT]
118127
ALL_LANGUAGE_NAMES = [lang.display_name for lang in ALL_LANGUAGES]
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import Foundation
2+
3+
{% if mod %}
4+
let MOD = {{ mod }}
5+
{% endif %}
6+
{% if yes_str %}
7+
let YES = "{{ yes_str }}"
8+
{% endif %}
9+
{% if no_str %}
10+
let NO = "{{ no_str }}"
11+
{% endif %}
12+
{% if prediction_success %}
13+
14+
func solve({{ formal_arguments }}) {
15+
{% if yes_str %}
16+
var ans = false
17+
18+
print(ans ? YES : NO)
19+
{% else %}
20+
var ans = 0
21+
22+
print(ans)
23+
{% endif %}
24+
}
25+
{% endif %}
26+
27+
func main() {
28+
{% if prediction_success %}
29+
var tokenIndex = 0, tokenBuffer = [String]()
30+
func readString() -> String {
31+
if tokenIndex >= tokenBuffer.count {
32+
tokenIndex = 0
33+
tokenBuffer = readLine()!.split(separator: " ").map { String($0) }
34+
}
35+
defer { tokenIndex += 1 }
36+
return tokenBuffer[tokenIndex]
37+
}
38+
func readInt() -> Int { Int(readString())! }
39+
func readDouble() -> Double { Double(readString())! }
40+
{{input_part}}
41+
solve({{ actual_arguments }})
42+
{% else %}
43+
// Failed to predict input format
44+
{% endif %}
45+
}
46+
47+
#if DEBUG
48+
let caseNumber = 1
49+
_ = freopen("in_\(caseNumber).txt", "r", stdin)
50+
#endif
51+
52+
main()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Foundation
2+
3+
func solve({{ formal_arguments }}) {
4+
5+
}
6+
7+
func main() {
8+
func readString() -> String { "" }
9+
func readInt() -> Int { 0 }
10+
func readDouble() -> Double { 0 }
11+
{{input_part}}
12+
solve({{ actual_arguments }})
13+
}
14+
15+
main()
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import Foundation
2+
3+
{% if mod %}
4+
let MOD = {{ mod }}
5+
{% endif %}
6+
{% if yes_str %}
7+
let YES = "{{ yes_str }}"
8+
{% endif %}
9+
{% if no_str %}
10+
let NO = "{{ no_str }}"
11+
{% endif %}
12+
{% if prediction_success %}
13+
14+
func solve({{ formal_arguments }}) {
15+
{% if yes_str %}
16+
var ans = false
17+
18+
print(ans ? YES : NO)
19+
{% else %}
20+
var ans = 0
21+
22+
print(ans)
23+
{% endif %}
24+
}
25+
{% endif %}
26+
27+
func main() {
28+
{% if prediction_success %}
29+
var tokenIndex = 0, tokenBuffer = [String]()
30+
func readString() -> String {
31+
if tokenIndex >= tokenBuffer.count {
32+
tokenIndex = 0
33+
tokenBuffer = readLine()!.split(separator: " ").map { String($0) }
34+
}
35+
defer { tokenIndex += 1 }
36+
return tokenBuffer[tokenIndex]
37+
}
38+
func readInt() -> Int { Int(readString())! }
39+
func readDouble() -> Double { Double(readString())! }
40+
{{input_part}}
41+
solve({{ actual_arguments }})
42+
{% else %}
43+
// Failed to predict input format
44+
{% endif %}
45+
}
46+
47+
#if DEBUG
48+
let caseNumber = 1
49+
_ = freopen("in_\(caseNumber).txt", "r", stdin)
50+
#endif
51+
52+
main()
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import Foundation
2+
3+
{% if mod is not none %}
4+
let MOD = {{ mod }}
5+
{% endif %}
6+
{% if yes_str is not none %}
7+
let YES = "{{ yes_str }}"
8+
{% endif %}
9+
{% if no_str is not none %}
10+
let NO = "{{ no_str }}"
11+
{% endif %}
12+
13+
func solve({{ formal_arguments }}) -> Bool {
14+
print("\(N) \(M)")
15+
guard H.count == N - 1 else {
16+
return false
17+
}
18+
for i in 0..<N-1 {
19+
guard H[i].count == M - 2 else {
20+
return false
21+
}
22+
for j in 0..<M-2 {
23+
if j > 0 {
24+
print(" ", terminator: "")
25+
}
26+
print("\(H[i][j])", terminator: "")
27+
}
28+
print("")
29+
}
30+
guard A.count == N - 1, B.count == N - 1 else {
31+
return false
32+
}
33+
for i in 0..<N-1 {
34+
print("\(A[i]) \(B[i])")
35+
}
36+
print("\(Q)")
37+
guard X.count == M + Q else {
38+
return false
39+
}
40+
for i in 0..<M + Q {
41+
print("\(X[i])")
42+
}
43+
44+
print(YES)
45+
print(NO)
46+
print(MOD)
47+
48+
return true
49+
}
50+
51+
func main() {
52+
var tokenIndex = 0, tokenBuffer = [String]()
53+
func readString() -> String {
54+
if tokenIndex >= tokenBuffer.count {
55+
tokenIndex = 0
56+
tokenBuffer = readLine()!.split(separator: " ").map { String($0) }
57+
}
58+
defer { tokenIndex += 1 }
59+
return tokenBuffer[tokenIndex]
60+
}
61+
func readInt() -> Int { Int(readString())! }
62+
func readDouble() -> Double { Double(readString())! }
63+
{{input_part}}
64+
_ = solve({{ actual_arguments }})
65+
}
66+
67+
main()

0 commit comments

Comments
 (0)