Pegjs: ノードの位置を追跡する機能を追加

作成日 2011年08月13日  ·  15コメント  ·  ソース: pegjs/pegjs

PEG.jsで生成されたパーサーは、現在、位置(行と列)を追跡しません。 この機能は非常に便利なので、追加したいと思います。

1つの方法は、一致結果として返される各オブジェクトにline $プロパティとcolumnプロパティを追加することです。

start = "a" b:"b" { return [b.line, b.column]; } // Returns [1, 2] on the input "ab".

もう1つの方法は、現在のルールの先頭の位置を参照して、アクション/述語内で特別なline $変数とcolumn変数を使用できるようにすることです。

start = "a" "b" { return [line, column]; } // Returns [1, 1] on the input "ab".

最初の方法はより柔軟性がありますが、この柔軟性は実際には必要ない場合があります。 どちらの方法で実装するかはまだわかりません。

どちらの方法でもパフォーマンスが低下します。 位置追跡が不要な場合にこれを防ぐには、パーサーの生成時に真の値を持つtrackPositionオプションがPEG.buildParserに渡された場合にのみ追跡を有効にする必要があります。

feature

最も参考になるコメント

@tomitrescakこの機能は、過去に数回変更されたようです。 詳細については、変更ログを参照してください。 tl; drは、文法でlocation()関数を使用する必要があるということです

全てのコメント15件

どちらのオプションも素晴らしいでしょう。 私のニーズのために単に行、列は大丈夫です。

私もこれの修正を探しています。 現在、computeErrorPosition()に基づいて何かをすばやくハッキングしましたが、いくつかのねじれがあります。

表面的には、最初のアプローチは2番目のアプローチよりも直感的に見えます。

私も最初のアプローチが好きです。

考えられる効率の1つは、name.positionを関数にすることです。これにより、遅延計算が可能になります。 これにより、行と列の2項目の配列が返される可能性があります。 すべてのアイテムの位置を計算したくない人のためのアイデアです。

後から考えると、開始文字と終了文字の位置を指定してから、位置を行/列に変換するヘルパー関数をライブラリに提供する方がよいようです。 一般的なケースでは、エラーがない限り行/列は必要ありません。エラーが発生すると、通常は1回だけ必要になります。

私は現在、 startPos0 $変数とpos変数を悪用することで、これをハック的な方法で行っています。これはハックっぽく感じますが、今のところは機能します。

公式の修正が行われるまで、この関数( computeErrorPositionの大まかなコピー)を文法の先頭に含めています。 少なくとも、それは私に_現在の_位置を与えます(個々のノードの位置ではありませんが):

  function computeCurrentPos() {
    /*
     * The first idea was to use |String.split| to break the input up to the
     * error position along newlines and derive the line and column from
     * there. However IE's |split| implementation is so broken that it was
     * enough to prevent it.
     */

    var line = 1;
    var column = 1;
    var seenCR = false;

    for (var i = 0; i < pos; i++) {
      var ch = input.charAt(i);
      if (ch === '\n') {
        if (!seenCR) { line++; }
        column = 1;
        seenCR = false;
      } else if (ch === '\r' | ch === '\u2028' || ch === '\u2029') {
        line++;
        column = 1;
        seenCR = true;
      } else {
        column++;
        seenCR = false;
      }
    }

    return { line: line, column: column, pos: pos };
  }

この問題は、一連のコミットによって修正されました。

これで、 trackLineAndColumnオプションをPEG.buildParser関数に渡すことができます。

var parser = PEG.buildParser(myGrammar, { trackLineAndColumn: true});

trackLineAndColumntrueに設定すると、アクションと述語に2つの新しい変数linecolumnが表示されます。 アクションの場合、これらの変数はアクションの式の開始位置を示し、述語では現在の位置を示します。 わずかに異なる動作は、予想される使用法によって動機付けられます。

行と列の追跡は、パフォーマンスを低下させるためオプションです(パーサーの速度が約3〜4倍遅くなります)。 将来的にはこれをいくらか最適化できるかもしれません(最初に機能させるようにしました)。

問題の説明で、この問題に対する別のアプローチについて言及していました。各一致結果にline #$プロパティとcolumnプロパティを追加することです。 このソリューションはよりクリーンでユーザーに好まれていましたが、文字列、数値、ブール値(一致結果として返されることが多い)などのプリミティブ値にプロパティを設定できないことに気付きました。 ラッピングオブジェクトのインスタンス( StringNumberBooleanなど)を返すことは回避策の可能性がありますが、ユーザーが作成したパーサーに微妙なバグが発生する可能性があります。これらのラッパーは、プリミティブとは少し異なる動作をします。 したがって、私は代替案を実施することにしました。

オンラインテストページは、この機能をサポートするように更新されますか?

@paulftwオンラインエディタは常に最新の安定バージョンのPEG.js(現在は0.6.2)を使用します。 PEG.js 0.7.0(この機能が含まれます)をリリースしたら、更新します。 予期せぬ事態が発生しない限り、これは4月の後半に発生します。

WebサイトのソースコードはGitHubで入手できるため、焦りがちな場合は、自分で実行して変更することができます。

すべての行と列が1ベースであるのに対し、JS配列、およびほとんどすべての最新の言語とライブラリは0ベースのインデックスを使用していることに気づきました。

その設計上の決定を元に戻すチャンスはありますか?

@paulftw行と列を0ベースとして報告するパーサジェネレータの例を挙げていただけますか?

私の決定の背後にある考え方は、これらの数値がユーザーに表示される可能性が最も高い(エラーメッセージ、ノード位置など)ため、1ベースのインデックス付けは0ベースよりも理にかなっているということです。 マシン処理の場合、 offset変数がおそらく最も頻繁に使用され、その変数は0ベースです。

その設計上の決定を元に戻すチャンスはありますか?

はい、私が確信した場合:-)

私はpeg.jsを使用して、Aceエディターでテキストを強調表示します。 当然のことながら、エースの行番号は0から始まります。
ただし、バイソンの場所は1ベースのようです。
http://git.savannah.gnu.org/cgit/bison.git/tree/src/location.c#n73

これが実際に当てはまる場合、私は議論をやめるべきです。

どんな例を見たいのかわからない。
現在、次のコードを使用してシンボル名を検索しています。

キャプター
= "" {return new Position(line-1、column-1); }

シンボル
= start:captor name:IDENT end:captor S * {return new Symbol(name、new Range(start、end)); }

@paulftwこの問題を別の問題に分割しました。 ユーザーが0.7.0を採用し、一般的な使用法が何であるかを確認するのを待ちます。

私はこれが長い間閉鎖されていることを知っていますが、どうすればこれを機能させることができますか? これにはかなりの初心者です。 「trackLineAndColumn ':true」フラグを使用して文法をコンパイルしましたが、ノードにはまだ行と列が含まれていません。 他に何が必要ですか?

あなたは次のように述べています、私はそれを使用する方法がわかりませんそれはどこかに文書化されていますか?

trackLineAndColumnをtrueに設定すると、アクションと述語に2つの新しい変数(行と列)が表示されます。 アクションの場合、これらの変数はアクションの式の開始位置を示し、述語では現在の位置を示します。 わずかに異なる動作は、予想される使用法によって動機付けられます。

@tomitrescakこの機能は、過去に数回変更されたようです。 詳細については、変更ログを参照してください。 tl; drは、文法でlocation()関数を使用する必要があるということです

このページは役に立ちましたか?
0 / 5 - 0 評価