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

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

    _item: $ => choice(
      $.a_instruction,
      $.c_instruction,
      $.label_declaration,
      $.comment,
      $._whitespace
    ),

    // A-instruction: @value or @symbol
    a_instruction: $ => seq(
      '@',
      choice(
        $.constant,
        $.symbol
      )
    ),

    // C-instruction: [dest=]comp[;jump]
    c_instruction: $ => seq(
      optional(seq($.dest, '=')),
      $.comp,
      optional(seq(';', $.jump))
    ),

    // Label declaration: (SYMBOL)
    label_declaration: $ => seq(
      '(',
      $.symbol,
      ')'
    ),

    // Constants: -32768 to 32767 (16-bit signed)
    constant: $ => /-?\d+/,

    // Symbols: letters, digits, _, ., $, : (not starting with digit)
    symbol: $ => choice(
      $.predefined_symbol,
      $.user_symbol
    ),

    // Predefined symbols
    predefined_symbol: $ => choice(
      // Virtual registers R0-R15
      /R(0|1[0-5]|[2-9])/,
      // Special symbols
      'SP', 'LCL', 'ARG', 'THIS', 'THAT',
      // I/O symbols
      'SCREEN', 'KBD'
    ),

    // User-defined symbols
    user_symbol: $ => /[A-Za-z_.$:][A-Za-z0-9_.$:]*/,

    // Destination field
    dest: $ => choice(
      'M', 'D', 'MD', 'A', 'AM', 'AD', 'AMD'
    ),

    // Computation field
    comp: $ => choice(
      // Zero and one
      '0', '1', '-1',
      // D register operations
      'D', '!D', '-D', 'D+1', 'D-1',
      // A register operations
      'A', '!A', '-A', 'A+1', 'A-1',
      // M register operations
      'M', '!M', '-M', 'M+1', 'M-1',
      // Two operand operations with D and A
      'D+A', 'D-A', 'A-D', 'D&A', 'D|A',
      // Two operand operations with D and M
      'D+M', 'D-M', 'M-D', 'D&M', 'D|M'
    ),

    // Jump field
    jump: $ => choice(
      'JGT', 'JEQ', 'JGE', 'JLT', 'JNE', 'JLE', 'JMP'
    ),

    // Comments
    comment: $ => token(seq('//', /.*/)),

    // Whitespace
    _whitespace: $ => /\s+/
  },

  extras: $ => [
    /\s/,
    $.comment
  ]
});
