シェブロテインのパーザー関数

パーザークラスの宣言から RULEメソッドのプロファイルを見る。

/**
 * A Parser that outputs a Concrete Syntax Tree.
 * See:
 *    - https://chevrotain.io/docs/tutorial/step3_adding_actions_root.html#alternatives
 *    - https://chevrotain.io/docs/guide/concrete_syntax_tree.html
 * For in depth docs.
 */
export declare class CstParser extends BaseParser {
  /**
   * Creates a Grammar Rule
   *
   * Note that any parameters of your implementation must be optional as it will
   * be called without parameters during the grammar recording phase.
   */
  protected RULE<F extends () => void>(
    name: string,
    implementation: F,
    config?: IRuleConfig<CstNode>
  ): ParserMethod<Parameters<F>, CstNode>
  //
  // 以下省略
  //
}

RULEの戻り値は ParserMethod<Parameters, CstNode> という型で、この型の定義は、

export type ParserMethod<ARGS extends unknown[], R> = (...args: ARGS) => R

ということで、RULEというDSLメソッドは、Fというルール実装関数を引数にして、パーザーメソッドを返す。

TypeScriptのクラス定義文スコープ内で代入文を書くとクラスメンバーが定義されるから、次のようにしてパーザーメソッドをクラスメンバーとしてセットできる。

public class MyParser extends chev.Parser {
  // ...
  myParserMethod = this.RULE("myRuleName", myRuleImplFunc);
  // ...
}

定義されたパーザーメソッドは、定義時の引数を取り、CstNode を返す関数となる。

ユーザー・パーザークラスに this.lexer を持たせるとして、

  setInput(document : string) {
    this.input = this.lexer.tokenize(document).tokens;
  }

としておけば、

parser.setInput(doc);
let cst : Cst = parser.myParserMethod();

と書ける。

Function.prototype.bind() (https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)参照を使って、パーザー関数(メソッド)を引っこ抜いて別オブジェクトで実行する事もできる。

let closure = parser.parser.myParserMethod.bind(otheParseObj);
let cst:Cst = closure();