13

CFGまたはPEG文法を、変更せずに直接コード補完の基礎として使用できるかどうか疑問に思っています。コード補完はIDEにあると聞いていますが、パフォーマンスを向上させるために、操作やマッサージを行ったり、ハードコーディングしたりすることもあります。

小さなDSLでコード補完したいので、文法はライブラリ関数などの知識を持つコード補完システムには役立たないことを十分に理解しています。

私が知っている限り、パーサー自体は、少なくとも次に何を期待するかを照会するためのシステムを提供する必要があります。

特に、 peg.js またはjisonを使用したJavaScriptコード補完ソリューションに興味があります

4

2 に答える 2

14

PEG文法からコード補完を使用してJavascriptエディターを構築するのはかなり簡単です。でそれを行う方法を説明しますPEG.js。前のステートメントが壊れたときに提案を提供できるようにするいくつかの緩い構文解析ルールを使用して文法を拡張する必要があります。これらの緩いルールは条件付きで処理する必要があります。そうしないと、2つの別個の文法が必要になります。1つはソースの解析用で、もう1つはコードの完了用です。Javascript述語(で利用可能PEG.js)を使用して、1つの文法を維持できます。のように見え、フラグが。の&{return laxParsing}場合、ルール全体が処理されます。パーサーの内部フラグを設定することで、緩い構文解析と厳密な構文解析を簡単に切り替えることができます。laxParsingtrue

ユーザーに簡単に提案を提供するには、わずかに生成されPEG.jsたパーサー(バージョン0.5)を変更して、解析エラー構造の位置(列と行の横)と期待値のリスト(エラーメッセージの横)で受け取る必要があります。準備したフラグメントをhttps://gist.github.com/1281239からコピーできます。

パーサーがある場合は、エディターでCTRL+SPACEキーを押すなどしてアタッチできます。これらがテキストソースで押された場合、カーソルの代わりに特別な解析不可能な記号を配置し(解析エラーを発生させるため)、パーサーを緩いモードで起動する必要があります。次に、提案のリストを含むエラーが表示されます。

いくつかの提案は構文であるだけでなく、参照(エンティティ、変数など)を定義します。特定の期待値が見つかったときに、これらの検索をトリガーできます(例VariableName)。同じソースを別の緩い解析モードで解析することでリストを提供できます(変数名のみをフィルタリングします)。

このアプローチの実用的な例とソースについては、https://github.com/mstefaniuk/Concrete-Freetextで確認できます。

于 2011-10-22T06:14:11.923 に答える
5

PEG.jsは、SyntaxErrorを生成するときに、かなりのコンテキストを提供します。たとえば、SQLの文法があり、次のようにフィードする場合です。

FOO > 10 A

次に、PEG.jsはこれを返します:

{
  "message": "Expected \"AND\", \"ORDER BY\" or end of input but \"A\" found.",
  "expected": [
    {
      "type": "literal",
      "value": "AND",
      "description": "\"AND\""
    },
    {
      "type": "literal",
      "value": "ORDER BY",
      "description": "\"ORDER BY\""
    },
    {
      "type": "end",
      "description": "end of input"
    }
  ],
  "found": "A",
  "offset": 9,
  "line": 1,
  "column": 10,
  "name": "SyntaxError"
}

文字列の0〜9文字( "FOO> 10")を解析しましたが、文字10で予期しないトークンが検出されました。次に、予期していたトークンのリストが表示されます:FOO > 10 AND、、。これらをクエリの有効な部分に追加すると、可能な補完の適切なセットが得られます。FOO > 10 ORDER BYFOO > 10

function getCompletions(pegParse, text) {
  var parsedText = pegParse(text);
  var completions = [];
  if (parsedText.expected) {
    var start = text.substr(0, parsedText.offset);
    parsedText.expected.forEach(function(expected) {
      if (expected.type != 'literal') return;
      var completion = start + expected.value;
      if (completion.substr(0, text.length) == text) {
        completions.push(completion);
      }
    });
  }
  return completions;
}

これは非常に単純です。実際のオートコンプリートは単なるリテラル以上のものに一致し、ユーザーが呼び出している関数の引数のリストなど、文法で使用できないコンテキストを利用するための何らかの方法が必要になります。

于 2014-11-13T21:51:59.523 に答える