module.exports = grammar({ name: 'langexp', word: $ => $.identifier, extras: $ => [ $._line_comment, $._block_comment, /\s/ ], rules: { // --- sources source_file: $ => repeat1($._statement), _statement: $ => choice( $.import, $.type_definition, $.function_definition, $.typeclass_definition, ), import: $ => seq( choice('::', 'import'), field('name', choice($.simple_name_identifier, '_')), optional(seq('=', field('module', $.simple_name_identifier))), optional(seq(':', repeat(choice( $.simple_type_identifier, $.simple_name_identifier, $.typeclass_identifier, seq('(',$.operator, ')'), )))), ';', ), constraint: $ => seq('?', $._expression), // --- definitions type_definition: $ => seq( optional($.definition_info), repeat($.annotation_info), optional('^'), field('name', $.simple_type_identifier), optional(seq(repeat($.argument_type_identifier), '=', choice($.variant_type, $.tuple_type))), choice(seq('{', repeat($.function_definition), '}'), ';') ), function_definition: $ => seq( optional($.definition_info), repeat($.annotation_info), repeat(seq($.constraint, ';')), /*optional(seq(*/optional(choice(choice('%', 'let'), choice('$', 'var')))/*, '.'))*/, field('name', $.simple_name_identifier), repeat(seq( optional($.annotation_identifier), $.argument_name_identifier, optional('?'), )), optional(seq(':', repeat1(seq( optional($.annotation_identifier), optional(choice(choice('->', 'out'), choice('<-', 'in'), choice('<>', 'ref'))), $.type, )))), choice(seq('=', choice(prec(2, $.block), seq($._super_expression, ';'))), ';'), ), typeclass_definition: $ => seq( optional($.definition_info), repeat($.annotation_info), $.typeclass_identifier, optional(seq(':', repeat($.typeclass_identifier))), choice(seq('{', repeat($.function_definition), '}'), ';'), ), // --- flow control case: $ => seq( choice(':=', '=:'), $._expression, optional(seq(choice('??', 'if'), $._expression)), optional(seq(choice('->', 'do'), $._expression)), ), match: $ => seq( $._expression, repeat1($.case), ), condition: $ => seq( choice('??', 'if'), $._expression, choice('->', 'do'), $._expression, repeat(seq( choice('!!', 'elif'), $._expression, choice('->', 'do'), $._expression, )), optional(seq(choice('!!->', 'else'), $._expression)), ), loop: $ => seq( choice('@', 'for'), optional(choice( field('condition', $._expression), seq(field('variable', $._expression), ':', field('interval', $._expression)), )), choice('->', 'do'), field('expression', $._expression), ), // --- operators comma_expression: $ => prec.left(seq($._super_expression, ',', $._super_expression)), operator_expression: $ => prec.left(choice( prec(4, seq($._expression, field('name', $.operator), $._expression)), prec(3, seq($._expression, field('name', $.operator_tail1), $._expression)), prec(2, seq($._expression, field('name', $.operator_tail2), $._expression)), prec(1, seq($._expression, field('name', $.operator_tail3), $._expression)), )), // --- continers block: $ => seq('{', repeat(seq($._super_expression, ';')), '}'), array: $ => seq('[[', repeat1($._scoped_expression), ']]'), // --- modifiers return: $ => seq(choice('return', 'bring'), field('value', $._expression)), name_definition: $ => seq( choice(choice('%', 'let'), choice('$', 'var')), choice($.simple_name_identifier, $.placeholder), ), array_access: $ => seq($._scoped_expression, '[', $._super_expression, ']'), tuple_access: $ => seq($._scoped_expression, '.', $.number_literal), loop_control: $ => choice('break', 'continue'), reference: $ => prec(-1, seq(choice(choice('<>', 'ref'), choice('<-', 'in')), $._scoped_expression)), suffix_expression: $ => seq($._scoped_expression, choice('?', '!')), // --- other name_expression: $ => seq( choice( seq($.type, '.', field('name', $.simple_name_identifier)), seq($._scoped_expression, '.', field('name', $.simple_name_identifier)), field('name', $._name_identifier), seq('(', field('name', $.operator), ')'), ), repeat(seq(optional($.annotation_identifier), $._scoped_expression)), ), constructor: $ => seq( $.type, repeat1(seq(optional($.annotation_identifier), $._scoped_expression)), ), lambda: $ => seq( '\\', repeat($.argument_name_identifier), '->', $._expression, ), // --- expression _super_expression: $ => choice( $.match, $.condition, $.loop, $.comma_expression, $._expression, ), _expression: $ => choice( $.operator_expression, $.return, $.name_expression, $.constructor, $.lambda, $._not_name_scoped_expression, ), _scoped_expression: $ => choice( $._name_identifier, $._not_name_scoped_expression, ), _not_name_scoped_expression: $ => choice( $.block, $.array, $.placeholder, $.name_definition, $.array_access, $.tuple_access, $.loop_control, $.reference, $.suffix_expression, $._literal, seq('(', $._super_expression, ')'), ), // --- type variant_type: $ => seq( optional('|'), $.tuple_type, repeat1(seq('|', $.tuple_type)), ), tuple_type: $ => seq( optional('&'), $._annotated_type, repeat(seq('&', $._annotated_type)), ), _annotated_type: $ => seq(optional($.annotation_identifier), $.type), type: $ => seq( optional('^'), field('name', $._type_identifier), optional('?'), optional(seq('[', repeat1($.type), ']')) ), // --- comments definition_info: $ => repeat1(seq(': ', /[^\n]*/)), annotation_info: $ => seq($.annotation_identifier, /[^\n]*/), _line_comment: $ => token(seq('//', /[^\n]*/)), _block_comment: $ => token(seq('/*', /([^*]|(\*[^/]))*/, '*/')), // --- tokens _name_identifier: $ => choice($.argument_name_identifier, $.simple_name_identifier), _type_identifier: $ => choice($.argument_type_identifier, $.simple_type_identifier), placeholder: $ => '_', simple_name_identifier: $ => token(seq(repeat(seq(/[a-z_][a-z0-9_]*/, '.')), /[a-z_][a-z0-9_]*/)), simple_type_identifier: $ => /([a-z_][a-z0-9_]*\.)*[A-Z][a-zA-Z0-9]*/, typeclass_identifier: $ => /([a-z_][a-z0-9_]*\.)*#[A-Z][a-zA-Z0-9]*/, argument_name_identifier: $ => /'[a-z_][a-z0-9_]*/, argument_type_identifier: $ => /'[A-Z][a-zA-Z0-9]*/, annotation_identifier: $ => /@[a-z_][a-z0-9_]*/, operator: $ => /([+\-*/%^!?|&,<>=]+)|\.+/, operator_tail1: $ => /[+\-*/%^!?|&,<>=]+\./, operator_tail2: $ => /[+\-*/%^!?|&,<>=]+\.\./, operator_tail3: $ => /[+\-*/%^!?|&,<>=]+\.\.\./, float_number_literal: $ => /[0-9]+\.[0-9]+/, number_literal: $ => /[0-9]+/, string_literal: $ => seq('\"', /([^\\\"]|(\\.))*/, '\"'), char_literal: $ => seq('\'\'', /[^\\\']|(\\.)/, '\'\''), bool_literal: $ => choice('true', 'false'), unit_literal: $ => '()', null_literal: $ => 'null', _literal: $ => choice( $.float_number_literal, $.number_literal, $.string_literal, $.char_literal, $.bool_literal, $.unit_literal, $.null_literal, ), identifier: $ => /([@'#]?[a-zA-Z0-9_]+)|([+\-*/%^!?|&,<>=]+\.?\.?\.?)|\.+/, } });