// Tree-sitter grammar for the Lux programming language
module.exports = grammar({
  name: 'lux',

  extras: $ => [
    /\s/,
    $.line_comment,
    $.doc_comment,
  ],

  conflicts: $ => [
    [$.primary_expression, $.pattern],
    [$.type_expression, $.primary_expression],
  ],

  word: $ => $.identifier,

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

    _declaration: $ => choice(
      $.function_declaration,
      $.let_declaration,
      $.type_declaration,
      $.effect_declaration,
      $.handler_declaration,
      $.trait_declaration,
      $.impl_declaration,
      $.import_declaration,
      $.export_declaration,
    ),

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

    // Function declaration
    function_declaration: $ => seq(
      'fn',
      field('name', $.identifier),
      optional($.type_parameters),
      $.parameter_list,
      ':',
      field('return_type', $.type_expression),
      optional($.effect_clause),
      optional($.property_clause),
      '=',
      field('body', $._expression),
    ),

    parameter_list: $ => seq(
      '(',
      optional(seq(
        $.parameter,
        repeat(seq(',', $.parameter)),
        optional(','),
      )),
      ')',
    ),

    parameter: $ => seq(
      field('name', $.identifier),
      ':',
      field('type', $.type_expression),
    ),

    type_parameters: $ => seq(
      '<',
      $.identifier,
      repeat(seq(',', $.identifier)),
      optional(','),
      '>',
    ),

    effect_clause: $ => seq(
      'with',
      '{',
      optional(seq(
        $.identifier,
        repeat(seq(',', $.identifier)),
        optional(','),
      )),
      '}',
    ),

    property_clause: $ => seq(
      'is',
      $.identifier,
      repeat(seq(',', $.identifier)),
    ),

    // Let declaration
    let_declaration: $ => seq(
      'let',
      field('name', $.identifier),
      optional(seq(':', field('type', $.type_expression))),
      '=',
      field('value', $._expression),
    ),

    // Type declaration
    type_declaration: $ => seq(
      'type',
      field('name', $.identifier),
      optional($.type_parameters),
      '=',
      field('definition', $.type_definition),
    ),

    type_definition: $ => choice(
      $.enum_definition,
      $.record_type,
      $.type_expression,
    ),

    enum_definition: $ => seq(
      repeat1(seq('|', $.variant)),
    ),

    variant: $ => seq(
      field('name', $.identifier),
      optional(choice(
        $.tuple_fields,
        $.record_fields,
      )),
    ),

    tuple_fields: $ => seq(
      '(',
      $.type_expression,
      repeat(seq(',', $.type_expression)),
      optional(','),
      ')',
    ),

    record_fields: $ => seq(
      '{',
      $.record_field,
      repeat(seq(',', $.record_field)),
      optional(','),
      '}',
    ),

    record_field: $ => seq(
      field('name', $.identifier),
      ':',
      field('type', $.type_expression),
    ),

    // Effect declaration
    effect_declaration: $ => seq(
      'effect',
      field('name', $.identifier),
      optional($.type_parameters),
      '{',
      repeat($.effect_operation),
      '}',
    ),

    effect_operation: $ => seq(
      'fn',
      field('name', $.identifier),
      $.parameter_list,
      ':',
      field('return_type', $.type_expression),
    ),

    // Handler declaration
    handler_declaration: $ => seq(
      'handler',
      field('name', $.identifier),
      ':',
      field('effect', $.identifier),
      '{',
      repeat($.handler_operation),
      '}',
    ),

    handler_operation: $ => seq(
      'fn',
      field('name', $.identifier),
      '(',
      optional(seq(
        $.identifier,
        repeat(seq(',', $.identifier)),
        optional(','),
      )),
      ')',
      '=',
      field('body', $._expression),
    ),

    // Trait declaration
    trait_declaration: $ => seq(
      'trait',
      field('name', $.identifier),
      optional($.type_parameters),
      '{',
      repeat($.trait_method),
      '}',
    ),

    trait_method: $ => seq(
      'fn',
      field('name', $.identifier),
      $.parameter_list,
      ':',
      field('return_type', $.type_expression),
    ),

    // Impl declaration
    impl_declaration: $ => seq(
      'impl',
      field('trait', $.identifier),
      'for',
      field('type', $.type_expression),
      '{',
      repeat($.function_declaration),
      '}',
    ),

    // Import/Export
    import_declaration: $ => seq(
      'import',
      $.import_path,
      optional($.import_clause),
    ),

    import_path: $ => seq(
      $.identifier,
      repeat(seq('.', $.identifier)),
    ),

    import_clause: $ => seq(
      '{',
      $.identifier,
      repeat(seq(',', $.identifier)),
      optional(','),
      '}',
    ),

    export_declaration: $ => seq(
      'export',
      '{',
      $.identifier,
      repeat(seq(',', $.identifier)),
      optional(','),
      '}',
    ),

    // Type expressions
    type_expression: $ => choice(
      $.identifier,
      $.generic_type,
      $.function_type,
      $.tuple_type,
      $.record_type,
      seq('(', $.type_expression, ')'),
    ),

    generic_type: $ => seq(
      $.identifier,
      '<',
      $.type_expression,
      repeat(seq(',', $.type_expression)),
      optional(','),
      '>',
    ),

    function_type: $ => seq(
      'fn',
      '(',
      optional(seq(
        $.type_expression,
        repeat(seq(',', $.type_expression)),
        optional(','),
      )),
      ')',
      ':',
      $.type_expression,
      optional($.effect_clause),
    ),

    tuple_type: $ => seq(
      '(',
      $.type_expression,
      ',',
      $.type_expression,
      repeat(seq(',', $.type_expression)),
      optional(','),
      ')',
    ),

    record_type: $ => seq(
      '{',
      optional(seq(
        $.record_field,
        repeat(seq(',', $.record_field)),
        optional(','),
      )),
      '}',
    ),

    // Expressions
    _expression: $ => choice(
      $.primary_expression,
      $.binary_expression,
      $.unary_expression,
      $.call_expression,
      $.member_expression,
      $.index_expression,
      $.if_expression,
      $.match_expression,
      $.block_expression,
      $.lambda_expression,
      $.run_expression,
      $.resume_expression,
      $.pipe_expression,
    ),

    primary_expression: $ => choice(
      $.identifier,
      $.number,
      $.string,
      $.char,
      $.boolean,
      $.unit,
      $.list_expression,
      $.tuple_expression,
      $.record_expression,
      seq('(', $._expression, ')'),
    ),

    // Literals
    number: $ => choice(
      $.integer,
      $.float,
    ),

    integer: $ => /\d+/,

    float: $ => /\d+\.\d+/,

    string: $ => choice(
      $.simple_string,
      $.interpolated_string,
    ),

    simple_string: $ => seq(
      '"',
      repeat(choice(
        $.string_content,
        $.escape_sequence,
      )),
      '"',
    ),

    interpolated_string: $ => seq(
      '"',
      repeat(choice(
        $.string_content,
        $.escape_sequence,
        $.interpolation,
      )),
      '"',
    ),

    string_content: $ => /[^"\\{]+/,

    escape_sequence: $ => /\\[nrt\\'"0{}\}]/,

    interpolation: $ => seq(
      '{',
      $._expression,
      '}',
    ),

    char: $ => seq(
      "'",
      choice(
        /[^'\\]/,
        $.escape_sequence,
      ),
      "'",
    ),

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

    unit: $ => seq('(', ')'),

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

    tuple_expression: $ => seq(
      '(',
      $._expression,
      ',',
      $._expression,
      repeat(seq(',', $._expression)),
      optional(','),
      ')',
    ),

    record_expression: $ => seq(
      '{',
      optional(seq(
        $.field_assignment,
        repeat(seq(',', $.field_assignment)),
        optional(','),
      )),
      '}',
    ),

    field_assignment: $ => seq(
      field('name', $.identifier),
      ':',
      field('value', $._expression),
    ),

    // Binary expressions
    binary_expression: $ => choice(
      prec.left(1, seq($._expression, '||', $._expression)),
      prec.left(2, seq($._expression, '&&', $._expression)),
      prec.left(3, seq($._expression, choice('==', '!='), $._expression)),
      prec.left(4, seq($._expression, choice('<', '>', '<=', '>='), $._expression)),
      prec.left(5, seq($._expression, choice('+', '-'), $._expression)),
      prec.left(6, seq($._expression, choice('*', '/', '%'), $._expression)),
    ),

    unary_expression: $ => prec(7, choice(
      seq('-', $._expression),
      seq('!', $._expression),
    )),

    // Pipe expression
    pipe_expression: $ => prec.left(0, seq(
      $._expression,
      '|>',
      $._expression,
    )),

    // Call expression
    call_expression: $ => prec(8, seq(
      field('function', $._expression),
      '(',
      optional(seq(
        $._expression,
        repeat(seq(',', $._expression)),
        optional(','),
      )),
      ')',
    )),

    // Member expression
    member_expression: $ => prec(9, seq(
      field('object', $._expression),
      '.',
      field('member', $.identifier),
    )),

    // Index expression
    index_expression: $ => prec(8, seq(
      field('object', $._expression),
      '[',
      field('index', $._expression),
      ']',
    )),

    // If expression
    if_expression: $ => prec.right(seq(
      'if',
      field('condition', $._expression),
      'then',
      field('then', $._expression),
      'else',
      field('else', $._expression),
    )),

    // Match expression
    match_expression: $ => seq(
      'match',
      field('value', $._expression),
      '{',
      repeat1($.match_arm),
      '}',
    ),

    match_arm: $ => seq(
      field('pattern', $.pattern),
      '=>',
      field('body', $._expression),
      optional(','),
    ),

    pattern: $ => choice(
      $.identifier,
      $.number,
      $.string,
      $.boolean,
      '_',
      $.constructor_pattern,
      $.tuple_pattern,
      $.record_pattern,
    ),

    constructor_pattern: $ => seq(
      field('name', $.identifier),
      optional(seq(
        '(',
        $.pattern,
        repeat(seq(',', $.pattern)),
        optional(','),
        ')',
      )),
    ),

    tuple_pattern: $ => seq(
      '(',
      $.pattern,
      ',',
      $.pattern,
      repeat(seq(',', $.pattern)),
      optional(','),
      ')',
    ),

    record_pattern: $ => seq(
      '{',
      $.field_pattern,
      repeat(seq(',', $.field_pattern)),
      optional(','),
      '}',
    ),

    field_pattern: $ => seq(
      field('name', $.identifier),
      optional(seq(':', field('pattern', $.pattern))),
    ),

    // Block expression
    block_expression: $ => seq(
      '{',
      repeat($.statement),
      optional($._expression),
      '}',
    ),

    statement: $ => seq(
      $.let_declaration,
    ),

    // Lambda expression
    lambda_expression: $ => seq(
      'fn',
      $.parameter_list,
      optional(seq(':', $.type_expression)),
      '=>',
      $._expression,
    ),

    // Run expression
    run_expression: $ => seq(
      'run',
      field('expression', $._expression),
      'with',
      '{',
      optional(seq(
        $.handler_binding,
        repeat(seq(',', $.handler_binding)),
        optional(','),
      )),
      '}',
    ),

    handler_binding: $ => seq(
      field('effect', $.identifier),
      '=',
      field('handler', $.identifier),
    ),

    // Resume expression
    resume_expression: $ => seq(
      'resume',
      '(',
      $._expression,
      ')',
    ),

    // Identifier
    identifier: $ => /[a-zA-Z_][a-zA-Z0-9_]*/,
  }
});
