verification-helper
verification-helper copied to clipboard
C# 対応
親 issue: #116
考えてなかったけどやってくれそうな人がいるので 同時に F# 対応も入るとうれしい
@riantkb @key-moon @cannorin
C#/F# には #include
に相当するものがないですが,csproj
や fsproj
から単一ファイルの生成をするという感じですか
仕様についてなのですが、C#の特性上関数やコード片を外に出すことができません。
ライブラリ的にはやはり関数なども置けたほうが嬉しいため、対応をするのであればC# scripting形式のファイルとしてライブラリを扱うのが良いのかな、とおもったりしています。
そうすると#load "[filepath]"
で別のライブラリをincludeのように参照できます。(例)
F# script (fsx) にも #load
プリミティヴがありそのように使うことができます (cf. https://docs.microsoft.com/ja-jp/dotnet/fsharp/tutorials/fsharp-interactive/)
Roslyn って言ってたのを昨日見たのでとりあえず名前だけ挙げておきます (私は何なのかよく分かってません) https://twitter.com/kymn_/status/1222084445970132992
Roslynは.NET Core
で使われているコンパイラで、Compiler as a Service
を掲げて構文解析等のAPIを提供しているものです。
C#のプロジェクトをライブラリにする場合はこれが方法となると思いますので、検討したいです。
パッと思いつくメリット・デメリットとしては、
メリット
- C#プロジェクトでライブラリが書ける
- 依存関係等をあまり意識しなくてよくなる(プロジェクトについてコンパイラがよしなにしてくれるので)
- 名前空間をつけられる(追記)
- テストについて、
NUnit
等のテスト用フレームワークを用いたテストの記述ができる(?)(かなりめんどくさそうではある) - 別用途への適用ができるかも(提出ファイル自動生成等)
デメリット
- 関数をライブラリ化する際に、Classで包まなければいけない(ボイラープレートが増える)
- 同じClass名のライブラリを作るのが煩雑になりそう(同一名前空間に同名Classが存在できないため)
- 実装が多分つらい
くらいでしょうか
https://github.com/riantkb/csharp/blob/83deb5ebbb7ecf65ab9a5987aab2feb461453ae8/test/BITTest.csx
こんなふうに書いて
dotnet script test/BITTest.csx
とすると動いたので,テストコードを c# script 形式で書くのはありかもしれないです.
ただ,c# script だと名前空間が定義できないので,ライブラリがちゃんと名前空間で分けられていたりすると動かないので少し微妙…
名前空間をつけている人がVerifyできなくなるのはあまり宜しくないので、生C#への対応は必須そうですね。それとは別にscriptでの手軽さは残したいので、簡単にできそうなscriptへの対応をまずは生やそうと思います。
list_attributes
が表すものについて、C#ではどのようにして対応するかを検討したいです。
list_attributes
はVerifyファイルの指定などに使われています。詳しくは以下の引用と、C++での実装を参考にしてください。(C++では#define
マクロの値をkey-value辞書として返すようにしています)
list_attributes
(設定情報の辞書を返す) だけは設計が自明でないんですが、うまくやってください。 実用的には「コンパイラが clang++ でかつ ulimit に失敗している場合のみ実行をスキップしたい」などの単純な条件分岐を含む設定が可能な仕様にする必要があります。
Originally posted by @kmyk in https://github.com/kmyk/online-judge-verify-helper/issues/116#issuecomment-579569384
C#の#define
はシンボルの定義のみしか行えないので、他の方法を考える必要があります。
私は#pragma
ディレクティブを使うのが最適かな、と思っているのですが、他に良い方法があれば教えて下さい。
.csx
の依存関係解析について、現在は #load
しか認識してくれないけど using
句も認識してくれるとうれしそう。
例:
https://github.com/camypaper/complib/blob/3805a404c327922398484caa8c2c1f79a059e7e9/Tests/Graph/HLtree.test.csx#L5
cc: @camypaper
現状の判定条件が行頭に #load
がある程度のゆるさなので
https://github.com/online-judge-tools/verification-helper/blob/daaa4d04f1625de766f6223c0f8a610077464841/onlinejudge_verify/languages/csharpscript.py#L61
https://github.com/camypaper/complib/blob/b1ba376a64964d1b6522b53b3ce26f763a4b4239/Tests/Graph/HLtree.test.csx#L2-L4
みたいにコメントで補足、というのでもなんとかなりそうです。 namespace の解析を真面目にするのはしんどい割に労力に見合わなさそうという気もしています。
なるほど、#r "./../../bin/complib.dll"
の時点ですでに全部が import されていて、using
は名前空間を省略できるようにするだけなのか。つらそう
申し訳ないがひとまずはコメントで補足する方式でお願いします :bow:
現状 3 つぐらい手は考えていて、今後やるにしても 2 程度が無難な落とし所な気が個人的にはしています
- roslyn などで頑張って解析
- pros: ちゃんとできるのがうれしい、ユーザ側が気にせず使える
- cons: 実装も保守も多分めちゃくちゃしんどい。
- [using static ディレクティブ] https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/keywords/using-static で使うライブラリのクラス名を明示させる(そういう用途のものではないが…)
- pros: コード中に使うライブラリのクラスを明示できる(し、コード書く時の静的解析にもかかる)
- cons: クラス名からファイル名は追跡できないのでそこのお世話をしないといけない。あとコードスニペットには対処不能(それは csx でやればいいけど)
-
#load filepath
をごまかして使う- pros: ほぼ何もしないのでコストが低い
- cons:ファイル名や依存関係に対するユーザ側の管理コストがかかる
現状の判定条件が行頭に
#load
がある程度のゆるさなので
これ、実はdotnet script
での実装をほぼそのまま取ってきてます(load
ディレクティブとかはifディレクティブの影響を受けないので、実はこれでもロードされる)
//hoge.csx
#if HOGE
/*
#load "fuga.csx"
*/
#endif
//fuga.csx
System.Console.WriteLine("fuga");
C# script
の理想的な使い方/依存関係の解決法は(たぶん)#load filepath
でのロードなので、usingでの解決やroslynに突っ込むといったことは(scriptでない)C#プロジェクトに対応する方で行うべきなので、いい加減やります。(テストもテストプロジェクトを作ってテストを書くことでいい感じになって欲しいと思っていますが、少し煩雑なのでたしかに共存可能だと嬉しいかもしれない)
それとは別に、RoslynでのC# script
のパースは1ファイルしか受け付けられない仕様になっているので、同一の解析器に突っ込むことはできなさそうです。なので、共存させる実装はかなり煩雑になりそうだなあという予測があります。
拙作のライブラリ https://github.com/kzrnm/SourceExpander で Roslyn による依存関係の解決を実現しているので、これを使用して実装できるかと思います。
私の方で実装してみようと思うので、完成したら Pull request を送ってみます。