tree-sitter description

This commit is contained in:
2026-07-13 17:21:36 +02:00
parent 5a958d9bfd
commit 9e75549d02
16 changed files with 150342 additions and 0 deletions
+594
View File
@@ -0,0 +1,594 @@
/// <reference types="tree-sitter-cli/dsl" />
// @ts-check
const PREC = {
RANGE: 1,
FALLBACK: 2,
OR: 3,
AND: 4,
COMPARE: 5,
SUM: 6,
PRODUCT: 7,
PREFIX: 8,
POSTFIX: 9,
};
module.exports = grammar({
name: 'brolang',
word: $ => $.identifier,
extras: $ => [/[ \t\r]/, $.comment],
conflicts: $ => [
[$.expression, $.qualified_identifier],
[$.constant_declaration, $.variable_declaration, $.expression],
[$.function_declaration],
[$.if_statement],
[$.enum_literal],
[$.array_type],
[$.array_type, $.expression],
[$.array_type, $.array_literal],
[$.expression_statement, $.parenthesized_expression],
],
rules: {
source_file: $ => repeat(choice($._newline, $._top_level_declaration)),
_top_level_declaration: $ => choice(
$.import_declaration,
$.function_declaration,
$.type_declaration,
$.global_constant_declaration,
$.global_variable_declaration,
),
import_declaration: $ => seq(
optional(seq(field('alias', $.identifier), '::', repeat($._newline))),
'import',
repeat($._newline),
field('path', $.string),
),
function_declaration: $ => seq(
field('name', $.identifier),
field('kind', choice('func', 'c_func')),
field('parameters', $.parameter_list),
repeat($._newline),
field('result', $.type),
optional(seq('!', field('error', $._error_type))),
optional(choice(
field('body', $.block),
seq(repeat1($._newline), field('body', $.block)),
)),
),
type_declaration: $ => prec(1, seq(
field('name', $.identifier),
'::',
repeat($._newline),
field('value', choice(
$.struct_type,
$.c_struct_type,
$.union_type,
$.enum_type,
$.opaque_type,
$.distinct_type,
$.alias_type,
)),
)),
global_constant_declaration: $ => seq(
field('name', $.identifier),
optional(field('type', $.type)),
'::',
repeat($._newline),
field('value', $._value),
),
global_variable_declaration: $ => seq(
field('name', $.identifier),
optional(field('type', $.type)),
'=',
repeat($._newline),
field('value', $._value),
),
struct_type: $ => seq('struct', repeat($._newline), $.record_body),
c_struct_type: $ => seq('c_struct', repeat($._newline), $.record_body),
opaque_type: _ => 'opaque',
distinct_type: $ => seq('distinct', field('type', $.type)),
alias_type: $ => seq('alias', field('type', $.type)),
union_type: $ => seq(
'union',
optional(seq('(', choice('enum', $.type), ')')),
repeat($._newline),
$.record_body,
),
enum_type: $ => seq(
'enum',
optional(seq('(', field('backing', $.type), ')')),
repeat($._newline),
$.enum_body,
),
record_body: $ => seq(
'{',
repeat(choice($._newline, seq($.record_field, optional(',')))),
'}',
),
record_field: $ => seq(
field('name', $.identifier),
field('type', choice($.type, $.struct_type)),
),
enum_body: $ => seq(
'{',
repeat(choice($._newline, seq($.enum_member, optional(',')))),
'}',
),
enum_member: $ => seq(
field('name', $.identifier),
optional(seq('=', optional('-'), field('value', $.integer))),
),
parameter_list: $ => seq(
'(',
commaSep($, choice($.parameter, '...')),
')',
),
parameter: $ => seq(
optional('$'),
field('name', choice($.identifier, $.sink)),
repeat(seq(',', repeat($._newline), field('name', choice($.identifier, $.sink)))),
field('type', $.type),
),
type: $ => prec.left(seq(
$._type_atom,
repeat(seq('|', $._type_atom)),
)),
_type_atom: $ => choice(
$.builtin_type,
$.named_type,
$.optional_type,
$.pointer_type,
$.array_type,
$.function_type,
),
named_type: $ => prec.right(seq(
$.qualified_identifier,
optional($.argument_list),
)),
optional_type: $ => seq('?', $.type),
pointer_type: $ => seq(
choice('@', '*'),
optional('mut'),
$.type,
),
array_type: $ => seq(
'[',
repeat($._newline),
optional(choice(
seq('*', ';', field('sentinel', $._type_constant)),
seq(';', field('sentinel', $._type_constant)),
seq(
field('length', choice($.sink, $.expression)),
optional(seq(';', field('sentinel', $._type_constant))),
),
)),
repeat($._newline),
']',
optional('mut'),
field('element', $.type),
),
function_type: $ => prec.right(seq(
choice('func', 'c_func'),
$.parameter_list,
repeat($._newline),
field('result', $.type),
optional(seq('!', field('error', $._error_type))),
)),
_error_type: $ => choice($.type, $.enum_type, $.union_type),
_type_constant: $ => seq(optional('-'), choice($.integer, $.character)),
builtin_type: _ => choice(
'void', 'anyopaque', 'bool', 'int', 'float', 'range',
'i8', 'i16', 'i32', 'i64', 'u8', 'u16', 'u32', 'u64',
'isize', 'usize', 'f32', 'f64',
'c_char', 'c_schar', 'c_uchar', 'c_short', 'c_ushort',
'c_int', 'c_uint', 'c_long', 'c_ulong', 'c_longlong',
'c_ulonglong', 'c_float', 'c_double', 'c_longdouble',
),
block: $ => seq(
'{',
repeat(choice($._newline, $.statement)),
'}',
),
statement: $ => choice(
$.constant_declaration,
$.variable_declaration,
$.assignment_statement,
$.return_statement,
$.yield_statement,
$.if_statement,
$.while_statement,
$.for_statement,
$.match_statement,
$.break_statement,
$.continue_statement,
$.defer_statement,
$.labeled_block,
$.block,
$.expression_statement,
),
constant_declaration: $ => seq(
field('name', choice($.identifier, $.sink)),
optional(field('type', $.type)),
'::',
repeat($._newline),
field('value', $._value),
),
variable_declaration: $ => seq(
field('name', choice($.identifier, $.sink)),
field('type', $.type),
'=',
repeat($._newline),
field('value', $._value),
),
assignment_statement: $ => seq(
field('left', $.expression),
field('operator', choice('=', '+=', '-=', '*=', '/=')),
repeat($._newline),
field('right', $._value),
),
expression_statement: $ => $.expression,
return_statement: $ => seq(
'return',
repeat($._newline),
field('value', $._value),
),
yield_statement: $ => seq(
'yield',
repeat($._newline),
optional(seq(':', field('label', $.identifier))),
field('value', $._value),
),
break_statement: $ => seq('break', optional(seq(':', field('label', $.identifier)))),
continue_statement: $ => seq('continue', optional(seq(':', field('label', $.identifier)))),
defer_statement: $ => seq('defer', repeat($._newline), field('body', $.statement)),
labeled_block: $ => seq(
field('label', $.identifier),
':',
repeat($._newline),
$.block,
),
if_statement: $ => seq(
'if',
repeat($._newline),
field('condition', $.expression),
optional($.capture_list),
repeat($._newline),
field('consequence', $._branch_body),
optional(seq(
repeat($._newline),
'else',
repeat($._newline),
field('alternative', $._branch_body),
)),
),
capture_list: $ => seq(
'|',
commaSep1($, choice($.identifier, $.sink)),
optional(seq(':', field('guard', $.expression))),
'|',
),
while_statement: $ => seq(
'while',
repeat($._newline),
field('condition', $.expression),
optional(seq(':', repeat($._newline), field('update', choice(
$.assignment_statement,
$.expression_statement,
seq('(', repeat($._newline), choice($.assignment_statement, $.expression_statement), repeat($._newline), ')'),
)))),
repeat($._newline),
optional(seq(field('label', $.identifier), ':', repeat($._newline))),
field('body', $.block),
),
for_statement: $ => seq(
'for',
repeat($._newline),
field('iterable', $.expression),
repeat($._newline),
'|',
optional('@'),
field('item', $.identifier),
optional(seq(',', field('index', $.identifier))),
'|',
repeat($._newline),
optional(seq(field('label', $.identifier), ':', repeat($._newline))),
field('body', $.block),
),
match_statement: $ => seq(
'match',
repeat($._newline),
field('subject', $.expression),
repeat($._newline),
'{',
repeat(choice($._newline, $.match_arm)),
'}',
),
match_arm: $ => seq(
field('pattern', choice('else', commaSep1($, $.expression))),
optional($.match_capture),
':',
repeat($._newline),
field('body', $._branch_body),
),
match_capture: $ => seq('|', optional('@'), field('name', choice($.identifier, $.sink)), '|'),
_branch_body: $ => $.statement,
_value: $ => choice(
$.labeled_block,
$.block,
$.if_statement,
$.while_statement,
$.for_statement,
$.match_statement,
$.expression,
),
expression: $ => choice(
$.binary_expression,
$.catch_expression,
$.unary_expression,
$.field_expression,
$.call_expression,
$.index_expression,
$.slice_expression,
$.postfix_expression,
$.struct_literal,
$.comptime_block,
$.function_literal,
$.struct_type,
$.array_type,
$.enum_literal,
$.array_literal,
$.parenthesized_expression,
$.identifier,
$.sink,
$.builtin_type,
$.integer,
$.float,
$.string,
$.multiline_string,
$.character,
$.boolean,
$.none,
$.undefined,
),
binary_expression: $ => choice(
prec.left(PREC.RANGE, seq(field('left', $.expression), field('operator', choice('..', '..=')), repeat($._newline), field('right', $.expression))),
prec.left(PREC.FALLBACK, seq(field('left', $.expression), field('operator', choice('orelse', 'catch')), repeat($._newline), field('right', $.expression))),
prec.left(PREC.OR, seq(field('left', $.expression), 'or', repeat($._newline), field('right', $.expression))),
prec.left(PREC.AND, seq(field('left', $.expression), 'and', repeat($._newline), field('right', $.expression))),
prec.left(PREC.COMPARE, seq(field('left', $.expression), field('operator', choice('==', '!=', '<', '<=', '>', '>=')), repeat($._newline), field('right', $.expression))),
prec.left(PREC.SUM, seq(field('left', $.expression), field('operator', choice('+', '-')), repeat($._newline), field('right', $.expression))),
prec.left(PREC.PRODUCT, seq(field('left', $.expression), field('operator', choice('*', '/')), repeat($._newline), field('right', $.expression))),
),
catch_expression: $ => prec.left(PREC.FALLBACK, seq(
field('value', $.expression),
'catch',
'|',
field('name', choice($.identifier, $.sink)),
'|',
repeat($._newline),
field('body', $.block),
)),
unary_expression: $ => prec(PREC.PREFIX, seq(
field('operator', choice('-', '&', '!', '$', 'try')),
repeat($._newline),
field('operand', $.expression),
)),
field_expression: $ => prec.left(PREC.POSTFIX, seq(
field('value', $.expression),
'.',
field('field', $.identifier),
)),
call_expression: $ => prec.left(PREC.POSTFIX, seq(
field('function', $.expression),
field('arguments', $.argument_list),
)),
argument_list: $ => prec(PREC.POSTFIX, seq('(', commaSep($, $.expression), ')')),
index_expression: $ => prec.left(PREC.POSTFIX, seq(
field('value', $.expression),
'[',
repeat($._newline),
field('index', $.expression),
repeat($._newline),
']',
)),
slice_expression: $ => prec.left(PREC.POSTFIX, seq(
field('value', $.expression),
'[',
repeat($._newline),
optional(field('start', $.expression)),
'..',
optional(field('end', $.expression)),
repeat($._newline),
']',
)),
postfix_expression: $ => prec.left(PREC.POSTFIX, seq(
field('value', $.expression),
field('operator', choice('?', '^')),
)),
struct_literal: $ => prec(PREC.POSTFIX, seq(
field('type', $.qualified_identifier),
optional($.argument_list),
field('fields', $.initializer_list),
)),
initializer_list: $ => seq(
'{',
choice(
repeat($._newline),
seq(
repeat($._newline),
$.field_initializer,
repeat(seq(repeat($._newline), ',', repeat($._newline), $.field_initializer)),
optional(seq(repeat($._newline), ',')),
repeat($._newline),
),
),
'}',
),
field_initializer: $ => seq(
field('name', $.identifier),
optional(seq('=', repeat($._newline), field('value', $.expression))),
),
enum_literal: $ => seq(
'.',
field('name', $.identifier),
optional($.variant_payload),
),
variant_payload: $ => seq(
'{',
choice(
repeat($._newline),
seq(
repeat($._newline),
choice(
$.expression,
seq(
$.keyed_field_initializer,
repeat(seq(repeat($._newline), ',', repeat($._newline), $.keyed_field_initializer)),
optional(seq(repeat($._newline), ',')),
),
),
repeat($._newline),
),
),
'}',
),
keyed_field_initializer: $ => seq(
field('name', $.identifier),
'=',
repeat($._newline),
field('value', $.expression),
),
array_literal: $ => seq('[', commaSep($, $.expression), ']'),
parenthesized_expression: $ => seq(
'(',
repeat($._newline),
$.expression,
repeat($._newline),
')',
),
comptime_block: $ => seq('$', repeat($._newline), $.block),
function_literal: $ => seq(
'func',
$.parameter_list,
repeat($._newline),
field('result', $.type),
optional(seq('!', field('error', $._error_type))),
repeat($._newline),
field('body', $.block),
),
qualified_identifier: $ => prec.right(seq(
field('qualifier', $.identifier),
optional(seq('.', field('name', $.identifier))),
)),
boolean: _ => choice('true', 'false'),
none: _ => 'none',
undefined: _ => 'undefined',
sink: _ => '_',
identifier: _ => /[A-Za-z_][A-Za-z0-9_]*/,
integer: _ => /[0-9]+/,
float: _ => token(prec(1, /[0-9]+\.[0-9]+/)),
string: $ => seq(
'"',
repeat(choice($.string_content, $.escape_sequence)),
'"',
),
string_content: _ => token.immediate(prec(1, /[^"\\\n]+/)),
escape_sequence: _ => token.immediate(/\\(?:\\|"|n|r|t|0)/),
multiline_string: _ => token(/`[^\n]*(?:\n[ \t]*`[^\n]*)*/),
character: _ => token(/'(?:[^'\\\n]|\\(?:\\|'|n|r|t|0))'/),
comment: _ => token(seq('#', /[^\n]*/)),
_newline: _ => /\n/,
},
});
function commaSep($, rule) {
return choice(
repeat($._newline),
seq(
repeat($._newline),
rule,
repeat(seq(repeat($._newline), ',', repeat($._newline), rule)),
optional(seq(repeat($._newline), ',')),
repeat($._newline),
),
);
}
function commaSep1($, rule) {
return seq(
rule,
repeat(seq(repeat($._newline), ',', repeat($._newline), rule)),
);
}