kazuk は null に触れてしまった

C# / .NET 系技術ネタ縛りでお送りしております

NParsec+ …で Excel を…CLI…(2) NParsec で Lexial Pattern をTDD


ぶっちゃけて言うと、NParsec のサンプルコードはTDD的な意味でイケテないです。

関数型言語でコンソールで結果がパタパタ出るのをそのままで置き換えるとしたら、いろんな要素宣言はどこに置くかって言ったら、当然にクラススコープでしょう、それを Parser プロパティの getter の中に置いちゃってるからどうにもなりません。

とりあえず中にある物を全部一回クラススコープに置きます。Field Initializer は記述順に動くことになってますので実行順序の問題とかは起こらないです。

ほんと?っていう人は C# Language Specification の 10.5.5 を見ましょう。

C:\Program Files(x86)\Microsoft Visual Studio 10.0\VC#\Specifications\1041

に規定でインストールされているドキュメントファイルです。

CSharp Language Specification 10.5.5 変数初期化子

10.5.4 で説明されている既定値の初期化は、変数初期化子を持つフィールドを含めて、すべてのフィールドに対して実行されます。したがって、クラスが初期化されると、そのクラスのすべての静的フィールドは最初に既定値に初期化され、その後、静的フィールド初期化子が記述順に実行されます。同様に、クラスのインスタンスが作成されると、そのインスタンスのすべてのインスタンス フィールドは最初に既定値に初期化され、その後、インスタンス フィールド初期化子が記述順に実行されます。

ちゃんと記述順に実行されるって書いてあるよね。

唯一の実行文である lazyExpr[0] = pExpr の前までをクラススコープでのフィールド定義とその初期化子に移します。

image

赤いニョロニョロの所を ReSharper でQuickFixする事のMake field ‘…’ static 連打です。(ReSharper無い人は頑張って static を打ち込め)

image

これでテストを書き加える事ができます。フィールド見てテストするって感じで… private だよ、って言われたら Make field ‘…’ internal でReSharper さんよろしく。(ReSharper無い人は頑張って internal を打ち込め)

image

って感じで、Pattern のテストはMatch メソッドを文字列を指定して呼び出すことの、想定されるマッチ長でテストを書きます。マッチしちゃいけない時はMISSMATCH( int で-1) が返されるようにします。

後は Pattern の書き方ですが、 Patterns には以下のメソッドがあります。

 

All( params Pattern[] pps ) パラメータで指定されたすべてのパターンにマッチする範囲を返します。

(AllPatternをReSharperで2回クリックでこんな結果。)

foreach (int l in
pps.Select(t => t.Match(underlying_text, starting_index, ending_index)))
{
    if (l == MISMATCH)
        return MISMATCH;
    if (l > ret)
        ret = l;
}

Enumerable.TakeWhile( l=>l!=MISSMATCH ).Aggregate( int.MaxValue, Math.Min )…としたい所なんですが TakeWhileはbraking した要素を返さないんでアレです。

拡張メソッドを作ってリファクタリングするかは各位にお任せ。

拡張メソッド追加で TakeWhileWithBrakingElement を作れば一行になりますね。

IsChar( char ch ) 指定された文字とマッチします。

InRange( char ch, char ch ) は指定された範囲とマッチします。

IsString( string pattern) 指定された文字列とマッチします。

Regex(Regex ) / Regex(string) 正規表現とマッチします

HasAtLeast(int n) 入力に残り文字数がn文字以上あればマッチします。

HasExact( int n) 入力に残り文字数がちょうど n文字あればマッチします。

Eof()  終わりにマッチします(HasExact(0)のエイリアス)

NotInRange( char c1,char c2 ) 範囲外の文字にマッチします。

Among ( params char[] cs) パラメータで指定された文字とマッチします。

NotAmong( params char[] cs) パラメータで指定された文字以外とマッチします。

Or( Pattern pp1, Pattern pp2) 二つのパターンの長い側のマッチ長を返します。

Repeat( int n, CharPredicate cp) 指定文字条件の n 文字の繰り返しにマッチします。

Many( int n,CharPredicate cp) 指定文字条件の n文字以上の繰り返しにマッチします。

Many( CharPredicate cp) 指定文字条件の 0 文字以上の繰り返しにマッチします。(存在しなかった場合にはマッチ長0が返されマッチ成功になります)

Some( int min,int max,CharPredicate cp) min文字以上、max文字以下の文字条件へのマッチを行います。

Longer(p1,p2) /Longest( params Pattern) 指定されたパターンの中で最長のマッチを返します。

Shorter/Shortest 最短のマッチを返します。

Never 常にミスマッチを返します。

Always 常にマッチ長0を返します。

IsWord() 正規表現 [a-zA-Z_][0-9a-zA-Z]* とマッチします。

…長くなってきたので割愛(飽きてきたともいう)

後は Pattern の Seq で連接だって知ってればいいんじゃないかな!

 

次回は Tokenizer でトークンの切り出しをします。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。