Для грамматических ломающих идентификаторов - PullRequest
1 голос
/ 24 марта 2019

Я пытаюсь сделать подсветку синтаксиса в Atom для игрушечного языка, над которым я работаю. Я на этапе, когда я определяю контекстно-свободную грамматику. Я строил это шаг за шагом и писал тесты по пути. Когда я добавил грамматику для цикла for in, он сломал мой тест для анализа идентификаторов, потому что идентификатор начинался с «in». Вот грамматика в ее нынешнем виде (извините за вставку такого большого количества кода, но я не знала, что может быть уместным, поэтому я просто добавила все это):

module.exports = grammar({
  name: 'MooLang',

  rules: {
    source_file: $ => repeat($._declaration),

    _declaration: $ => choice(
      $.variable_declaration,
      $._statement
    ),

    variable_declaration: $ => seq(
      choice('var', 'let'),
      $.identifier,
      optional(seq(
        ':', $._type
      )),
      optional(seq(
        '=', $._expression
      )),
      $.eol
    ),

    _statement: $ => choice(
      $.for_statement,
      $.expression_statement
    ),

    for_statement: $ => prec(0, seq(
      'for',
      '(',
      choice(
        $.variable_declaration,
        $.expression_statement,
      ),
      'in',
      $._expression,
      ')',
      $._statement
    )),

    expression_statement: $ => prec(1, seq(
      $._expression,
      $.eol
    )),

    _expression: $ => choice(
      $.assignment,
      $.comparison_expression,
      $.addition_expression,
      $.multiplication_expression,
      $.unary_expression,
      prec(5, $.primary),
      prec(-1, $._type) // TODO:(Casey) Remove this
    ),

    assignment: $ => prec.right(0, seq(
      $.identifier,
      '=',
      $._expression
    )),

    comparison_expression: $ => prec.left(1, seq(
      $._expression,
      choice('<', '<=', '>', '>=', '==', '!='),
      $._expression
    )),

    addition_expression: $ => prec.left(2, seq(
      $._expression,
      choice('+', '-'),
      $._expression
    )),

    multiplication_expression: $ => prec.left(3, seq(
      $._expression,
      choice('*', '/', '%'),
      $._expression
    )),

    unary_expression: $=> prec.right(4, seq(
      choice('!', '-'),
      $.primary
    )),

    _type: $ => choice(
      $.primitive_type,
      $.list_type,
      $.map_type
    ),

    primitive_type: $ => choice(
      'bool', 'string',
      'int8', 'int16', 'int32', 'int64',
      'uint8', 'uint16', 'uint32', 'uint64',
      'float32', 'float64'
    ),

    list_type: $ => seq(
      '[',
      $._type,
      ']'
    ),

    map_type: $ => seq(
      '{',
      $._type,
      ':',
      $._type,
      '}'
    ),

    primary: $ => choice(
      $.bool_literal,
      $.list_literal,
      $.map_literal,
      $.parenthetical_expression,
      $.identifier,
      $.number
    ),

    bool_literal: $ => choice('true', 'false'),

    list_literal: $ => seq(
      '[',
      optional(seq(
        $._expression,
        repeat(seq(
          ',',
          $._expression
        )),
        optional(','),
      )),
      ']'
    ),

    map_literal: $ => seq(
      '{',
      optional(seq(
        $._expression,
        ':',
        $._expression,
        repeat(seq(
          ',',
          $._expression,
          ':',
          $._expression,
        )),
      )),
      '}'
    ),

    parenthetical_expression: $ => seq(
      '(',
      $._expression,
      ')'
    ),

    identifier: $ => prec(99, /[a-zA-Z_][a-zA-Z0-9_]*/),

    number: $ => prec(99, /\d+(_\d+)*(\.\d+)?/),

    eol: $ => '\n'
  }
});

Вот соответствующие тесты:

==================
Identifier Tests
==================

13india

---

(source_file
  (expression_statement (primary (number)) (MISSING))
  (expression_statement (primary (identifier)) (eol))
)

==================
For Tests
==================

for (var a in people) a + 1

---

(source_file
  (for_statement (variable_declaration (identifier)) (primary (identifier)) (expression_statement (addition_expression (primary (identifier)) (primary (number))) (eol)))
)

Пока я не добавил грамматику для цикла for, все тесты идентификаторов проходили, но теперь я получаю следующий вывод:

Testing Error Output

Я предполагаю, что он находит неожиданное «d», потому что думает, что это ключевое слово «in». Но я не могу понять, почему он так подумал, поскольку он не соответствует ничему другому в цикле for.

...