Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support C# #153

Merged
merged 17 commits into from
Sep 1, 2019
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ before_install:
- 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
- sudo apt-get install rustc g++-4.9 openjdk-8-jdk nim dmd-compiler mono-complete
- sudo ln -f -s /usr/bin/g++-4.9 /usr/bin/g++

install:
Expand Down
175 changes: 175 additions & 0 deletions atcodertools/codegen/code_generators/cs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
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 _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(int {loop_var} = 0;{loop_var} < {len};{loop_var}++)".format(
loop_var=loop_var,
len=index.get_length()
) + "{"


class CSharpCodeGenerator:

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(2)).join(lines)

def _convert_type(self, type_: Type) -> str:
if type_ == Type.float:
return "double"
elif type_ == Type.int:
return "long"
elif type_ == Type.str:
return "string"
else:
raise NotImplementedError

def _get_declaration_type(self, var: Variable):
ctype = self._convert_type(var.type)
if var.dim_num() == 0:
return ctype
else:
return "{}[{}]".format(ctype, "," * (var.dim_num() - 1))

def _actual_arguments(self) -> str:
"""
:return the string form of actual arguments e.g. "N, K, a"
"""
return ", ".join([
v.name if v.dim_num() == 0 else '{}'.format(v.name)
for v in self._format.all_vars()])

def _formal_arguments(self):
"""
:return the string form of formal arguments e.g. "int N, int K, std::vector<int> a"
"""
return ", ".join([
"{decl_type} {name}".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 E.g. array[1..n] -> std::vector<int> array = std::vector<int>(n-1+1);
"""
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
ret = "{decl_type} {name}".format(
decl_type=self._get_declaration_type(var), name=var.name)
if len(dims) > 0:
t = self._convert_type(var.type)
d = []
for dim in dims:
d.append(str(dim))
ret += " = new {type}[{dims}]".format(type=t, dims=",".join(d))
ret += ";"
return ret

def _input_code_for_var(self, var: Variable) -> str:
name = self._get_var_name(var)
if var.type == Type.float:
return '{name} = cin.ReadDouble;'.format(name=name)
elif var.type == Type.int:
return '{name} = cin.ReadLong;'.format(name=name)
elif var.type == Type.str:
return '{name} = cin.Read;'.format(name=name)
else:
raise NotImplementedError

@staticmethod
def _get_var_name(var: Variable):
name = var.name
if var.dim_num() >= 1:
name += "[i"
if var.dim_num() >= 2:
name += ",j"
name += "]"
return name

def _render_pattern(self, pattern: Pattern):
lines = []
for var in pattern.all_vars():
lines.append(self._generate_declaration(var))

representative_var = pattern.all_vars()[0]
if isinstance(pattern, SingularPattern):
lines.append(self._input_code_for_var(representative_var))
elif isinstance(pattern, ParallelPattern):
lines.append(_loop_header(representative_var, False))
for var in pattern.all_vars():
lines.append("{indent}{line}".format(indent=self._indent(1),
line=self._input_code_for_var(var)))
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():
lines.append("{indent}{line}".format(indent=self._indent(2),
line=self._input_code_for_var(var)))
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 = CSharpCodeGenerator(
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
)
14 changes: 12 additions & 2 deletions atcodertools/common/language.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import re
from typing import Pattern, Callable

from atcodertools.codegen.code_generators import cpp, java, rust, python, nim, d
from atcodertools.codegen.code_generators import cpp, java, rust, python, nim, d, cs
from atcodertools.codegen.models.code_gen_args import CodeGenArgs
from atcodertools.tools.templates import get_default_template_path

Expand Down Expand Up @@ -103,5 +103,15 @@ def from_name(cls, name: str):
default_code_style=CodeStyle(indent_width=2)
)

ALL_LANGUAGES = [CPP, JAVA, RUST, PYTHON, NIM, DLANG]
CSHARP = Language(
name="cs",
display_name="C#",
extension="cs",
submission_lang_pattern=re.compile(".*C# \\(Mono.*"),
default_code_generator=cs.main,
default_template_path=get_default_template_path('cs'),
)


ALL_LANGUAGES = [CPP, JAVA, RUST, PYTHON, NIM, DLANG, CSHARP]
ALL_LANGUAGE_NAMES = [lang.display_name for lang in ALL_LANGUAGES]
63 changes: 63 additions & 0 deletions atcodertools/tools/templates/default_template.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using static System.Console;
using static System.Math;
using System.Diagnostics;

public class Program{
{% if mod %}
const long MOD = {{ mod }};
{% endif %}
{% if yes_str %}
const string YES = "{{ yes_str }}";
{% endif %}
{% if no_str %}
const string NO = "{{ no_str }}";
{% endif %}

public static void Main(string[] args){
ConsoleInput cin = new ConsoleInput(Console.In, ' ');
{% if prediction_success %}
{{ input_part }}
new Program().Solve({{ actual_arguments }});
{% else %}
// Failed to predict input format
{% endif %}
}

{% if prediction_success %}
public void Solve({{ formal_arguments }}){

}
{% endif %}
}

public class ConsoleInput{
private readonly System.IO.TextReader _stream;
private char _separator = ' ';
private Queue<string> inputStream;
public ConsoleInput(System.IO.TextReader stream, char separator = ' '){
this._separator = separator;
this._stream = stream;
inputStream = new Queue<string>();
}
public string Read{
get{
if (inputStream.Count != 0) return inputStream.Dequeue();
string[] tmp = _stream.ReadLine().Split(_separator);
for (int i = 0; i < tmp.Length; ++i)
inputStream.Enqueue(tmp[i]);
return inputStream.Dequeue();
}
}
public string ReadLine { get { return _stream.ReadLine(); } }
public int ReadInt { get { return int.Parse(Read); } }
public long ReadLong { get { return long.Parse(Read); } }
public double ReadDouble { get { return double.Parse(Read); } }
public string[] ReadStrArray(long N) { var ret = new string[N]; for (long i = 0; i < N; ++i) ret[i] = Read; return ret;}
public int[] ReadIntArray(long N) { var ret = new int[N]; for (long i = 0; i < N; ++i) ret[i] = ReadInt; return ret;}
public long[] ReadLongArray(long N) { var ret = new long[N]; for (long i = 0; i < N; ++i) ret[i] = ReadLong; return ret;}
}
Empty file added tests/check_autopep8
Empty file.
46 changes: 46 additions & 0 deletions tests/resources/test_codegen/template.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using static System.Console;
using static System.Math;

public class Program{
public static void Main(string[] args){
ConsoleInput cin = new ConsoleInput(Console.In, ' ');
${input_part}
new Program().Solve(${actual_arguments});
}

public void Solve(${formal_arguments}){

}
}

public class ConsoleInput{
private readonly System.IO.TextReader _stream;
private char _separator = ' ';
private Queue<string> inputStream;
public ConsoleInput(System.IO.TextReader stream, char separator = ' '){
this._separator = separator;
this._stream = stream;
inputStream = new Queue<string>();
}
public string Read{
get{
if (inputStream.Count != 0) return inputStream.Dequeue();
string[] tmp = _stream.ReadLine().Split(_separator);
for (int i = 0; i < tmp.Length; ++i)
inputStream.Enqueue(tmp[i]);
return inputStream.Dequeue();
}
}
public string ReadLine { get { return _stream.ReadLine(); } }
public int ReadInt { get { return int.Parse(Read); } }
public long ReadLong { get { return long.Parse(Read); } }
public double ReadDouble { get { return double.Parse(Read); } }
public string[] ReadStrArray(long N) { var ret = new string[N]; for (long i = 0; i < N; ++i) ret[i] = Read; return ret;}
public int[] ReadIntArray(long N) { var ret = new int[N]; for (long i = 0; i < N; ++i) ret[i] = ReadInt; return ret;}
public long[] ReadLongArray(long N) { var ret = new long[N]; for (long i = 0; i < N; ++i) ret[i] = ReadLong; return ret;}
}
56 changes: 56 additions & 0 deletions tests/resources/test_codegen/template_jinja.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using static System.Console;
using static System.Math;

public class Program{
{% if mod %}
const long MOD = {{ mod }};
{% endif %}
{% if yes_str %}
const string YES = "{{ yes_str }}";
{% endif %}
{% if no_str %}
const string NO = "{{ no_str }}";
{% endif %}

public static void Main(string[] args){
ConsoleInput cin = new ConsoleInput(Console.In, ' ');
{{ input_part }}
new Program().Solve({{ actual_arguments }});
}

public void Solve({{ formal_arguments }}){

}
}

public class ConsoleInput{
private readonly System.IO.TextReader _stream;
private char _separator = ' ';
private Queue<string> inputStream;
public ConsoleInput(System.IO.TextReader stream, char separator = ' '){
this._separator = separator;
this._stream = stream;
inputStream = new Queue<string>();
}
public string Read{
get{
if (inputStream.Count != 0) return inputStream.Dequeue();
string[] tmp = _stream.ReadLine().Split(_separator);
for (int i = 0; i < tmp.Length; ++i)
inputStream.Enqueue(tmp[i]);
return inputStream.Dequeue();
}
}
public string ReadLine { get { return _stream.ReadLine(); } }
public int ReadInt { get { return int.Parse(Read); } }
public long ReadLong { get { return long.Parse(Read); } }
public double ReadDouble { get { return double.Parse(Read); } }
public string[] ReadStrArray(long N) { var ret = new string[N]; for (long i = 0; i < N; ++i) ret[i] = Read; return ret;}
public int[] ReadIntArray(long N) { var ret = new int[N]; for (long i = 0; i < N; ++i) ret[i] = ReadInt; return ret;}
public long[] ReadLongArray(long N) { var ret = new long[N]; for (long i = 0; i < N; ++i) ret[i] = ReadLong; return ret;}
}
Loading