Skip to content

Instantly share code, notes, and snippets.

@Kuniwak Kuniwak/major-linters.md
Last active Aug 29, 2015

Embed
What would you like to do?
Major linter の戦略と実装

Major linter の戦略と実装

Perl::Critic

  • 構文解析器: PPI

  • ポリシーはオブジェクト: Perl::Critic::Policy

  • 違反もオブジェクト: Perl::Critic::Violation

  • 処理の流れ

    1. 有効な検査ポリシーが設定される
    2. 検査ポリシーごとに以下を繰り返す(Perl::Critic#_gather_violations $doc : @violations
      1. 検査ポリシーが解析に必要な要素名を宣言する(Perl::Critic::Policy#applies_to : String[]
      2. 該当要素ごとに以下が繰り返される
        1. この検査ポリシーにこの該当要素とドキュメント全体が渡される(Perl::Critic::Policy#violates $element $doc: @violations
        2. この検査ポリシーが違反項目を配列で返す
        3. この検査ポリシーが違反項目をひとつの配列にまとめる
      3. この検査ポリシーが発見したすべての違反項目を返す
    3. 検査ポリシーが発見したすべての違反項目をひとつの配列にまとめる
    4. すべての違反項目に対して統計項目がまとめられる(Perl::Critic::Statistics#accumlate $doc $violations
    5. 表示のための処理(違反項目表示数制限・ソート)がおこなわれる
    6. 表示される
  • Perl::Critic::Policy の責務

    • 判定に必要な要素名の宣言
    • 違反判定
    • 違反の重要度(severity)の保持
    • 違反項目情報の作成(違反項目名・説明・該当要素)
      • 項目名: Variable declared in conditional statement
      • 説明: Declare variables outside of the condition
      • 該当要素: PPI::Element
  • Perl::Critic::Violation の責務

    • 違反項目名の保持
    • 違反項目に関する説明の保持(Perl Best Practiceのページ番号)
    • 違反位置の取得
    • 違反情報の表示文字列化(各情報をsprintfでフォーマット)[cool!]
  • 設定ファイル: .perlcritic

      [-NamingConventions::Capitalization]
      [-TestingAndDebugging::RequireUseWarnings]
    
      [BuiltinFunctions::RequireBlockGrep]
      severity = 2
    
      [CodeLayout::ProhibitHardTabs]
      severity = 1
    

rubocop

  • 構文解析器: Parser

  • 闇が深く断念

    • 命名が闇
    • ところどころ TODO: bad design という素敵なお言葉
  • 設定ファイル: rubocop.yml

      Style/VariableName:
        EnforcedStyle: snake_case
        SupportedStyles:
          - snake_case
          - camelCase
    
      Style/WhileUntilModifier:
        MaxLineLength: 80
    

JSHint

  • 構文解析器:自前

  • エラー出力関数は warning(code, t, a, b, c, d)

  • メインルーチンが構文木をなめていく過程で、違反を判定

  • 設定ファイル: .jshintrc

      {
          "maxcomplexity" : false,    // {int} Max cyclomatic complexity per function
          "maxlen"        : false,    // {int} Max number of characters per line
      }
    

JSLint

  • 構文解析器:自前
  • メインルーチンからエラー出力関数までの仕組みはほぼ JSHint と同じ
  • 設定ファイルでは変更出来なさそう
    • かわりに /*jslint*/ /*properties*/ ディレクティブがある

ESLint

  • 構文解析器:esprima(木の巡回にestraverse使ってる)

  • ルールは lib/rules 以下に定義されている関数

    • 引数は context

    • esprima の解析した AST ノード名をキーとした関数を持つオブジェクトを返す

    • この関数が出力までの責任を持つ

        return {
          "CallExpression": function(node) {
            var result;
            if (result) {
              report(context, node, result);
            }
          }
        };
      
  • 処理の流れ

    1. すべてのルールが読み込まれる
    2. 無効設定されたルールを除去され、有効なルールのみが残る
    3. 有効なルールについて以下を繰り返す
      1. ルールが要求しているAST要素名を取得する
      2. このAST要素名について、 estraverse による AST 要素の訪問/脱出イベントを listen する
    4. estraverse によって AST が巡回される
      1. ルールが要求しているAST要素名を訪問したとき、ルールの判定メソッドが実行される
      2. 違反が見つかった場合は、違反項目情報(説明・該当要素)を報告する
      3. 報告された違反を配列にまとめていく
    5. まとめられた違反を formater を使って表示する
  • rule の責務

    • 判定に必要なトークン名の宣言
    • 違反判定
    • 違反項目情報の作成(説明・該当要素)
      • 説明: Expected '===' and instead saw '=='.
      • 該当位置: (要素が位置をもっていなければ)
      • 該当要素: Esprima.Node
    • ruleId は RuleCreator によって割り当てられる
  • 設定ファイル:.eslintrc, eslint.json

      module.exports = {
          rules: {
              semi: 2
          }
      };
    

vim-vimlint

  • 構文解析器:vim-vimlparser
  • ルールは autoload/vimlinter.vim の関数群
  • トークンの種類ごとに1つの検査メソッドが走って解析される

pep8

  • 構文解析機:compile(標準)
  • ルールは 3 つに分類された静的関数群:
    • 物理行(正規表現)
    • 論理行(正規表現)
    • AST(構文エラーのみをチェック)
  • それぞれの静的関数はtoken列の処理と混同されている

やりたいこと

  • ルールをオブジェクトにしたい
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.