Skip to content

Commit

Permalink
Support C# (#153)
Browse files Browse the repository at this point in the history
* Support C#
  • Loading branch information
chaemon authored and kyuridenamida committed Sep 1, 2019
1 parent 302d80b commit 1126750
Show file tree
Hide file tree
Showing 16 changed files with 913 additions and 5 deletions.
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

0 comments on commit 1126750

Please sign in to comment.