tree-sitter description
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
/build/
|
/build/
|
||||||
|
/grammars/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
id = "brolang"
|
||||||
|
name = "Brolang"
|
||||||
|
version = "0.1.0"
|
||||||
|
schema_version = 1
|
||||||
|
authors = ["Brolang contributors"]
|
||||||
|
description = "Brolang language support"
|
||||||
|
repository = "ssh://git@gitea.hl-valdemar.dev:2222/hl-valdemar/brolang.git"
|
||||||
|
languages = ["languages/brolang"]
|
||||||
|
|
||||||
|
[grammars.brolang]
|
||||||
|
repository = "file:///Users/valdemar/Developer/Personal/Languages/brolang"
|
||||||
|
rev = "zed-dev"
|
||||||
|
path = "tree-sitter-brolang"
|
||||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,14 @@
|
|||||||
|
name = "Brolang"
|
||||||
|
grammar = "brolang"
|
||||||
|
path_suffixes = ["bro", "hon"]
|
||||||
|
line_comments = ["# "]
|
||||||
|
hard_tabs = true
|
||||||
|
tab_size = 4
|
||||||
|
autoclose_before = ";:.,=}])>"
|
||||||
|
brackets = [
|
||||||
|
{ start = "{", end = "}", close = true, newline = true },
|
||||||
|
{ start = "[", end = "]", close = true, newline = true },
|
||||||
|
{ start = "(", end = ")", close = true, newline = true },
|
||||||
|
{ start = "'", end = "'", close = true, newline = false, not_in = ["comment", "string"] },
|
||||||
|
{ start = "\"", end = "\"", close = true, newline = false, not_in = ["comment", "string"] },
|
||||||
|
]
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
(comment) @comment
|
||||||
|
|
||||||
|
[
|
||||||
|
(string)
|
||||||
|
(multiline_string)
|
||||||
|
] @string
|
||||||
|
|
||||||
|
(character) @string
|
||||||
|
(escape_sequence) @string.escape
|
||||||
|
|
||||||
|
[
|
||||||
|
(integer)
|
||||||
|
(float)
|
||||||
|
] @number
|
||||||
|
|
||||||
|
(boolean) @boolean
|
||||||
|
|
||||||
|
[
|
||||||
|
(none)
|
||||||
|
(undefined)
|
||||||
|
] @constant.builtin
|
||||||
|
|
||||||
|
(builtin_type) @type.builtin
|
||||||
|
(named_type) @type
|
||||||
|
|
||||||
|
(type_declaration name: (identifier) @type)
|
||||||
|
(function_declaration name: (identifier) @function)
|
||||||
|
(parameter name: (identifier) @variable.parameter)
|
||||||
|
|
||||||
|
(call_expression function: (expression (identifier) @function))
|
||||||
|
(call_expression function: (expression (field_expression field: (identifier) @function)))
|
||||||
|
(field_expression field: (identifier) @property)
|
||||||
|
(field_initializer name: (identifier) @property)
|
||||||
|
(keyed_field_initializer name: (identifier) @property)
|
||||||
|
(record_field name: (identifier) @property)
|
||||||
|
(enum_member name: (identifier) @property)
|
||||||
|
(enum_literal name: (identifier) @property)
|
||||||
|
|
||||||
|
(import_declaration alias: (identifier) @variable)
|
||||||
|
(opaque_type) @keyword
|
||||||
|
|
||||||
|
[
|
||||||
|
"func"
|
||||||
|
"c_func"
|
||||||
|
"struct"
|
||||||
|
"c_struct"
|
||||||
|
"union"
|
||||||
|
"enum"
|
||||||
|
"distinct"
|
||||||
|
"alias"
|
||||||
|
"import"
|
||||||
|
"return"
|
||||||
|
"try"
|
||||||
|
"catch"
|
||||||
|
"mut"
|
||||||
|
"orelse"
|
||||||
|
"and"
|
||||||
|
"or"
|
||||||
|
"if"
|
||||||
|
"while"
|
||||||
|
"for"
|
||||||
|
"break"
|
||||||
|
"continue"
|
||||||
|
"defer"
|
||||||
|
"yield"
|
||||||
|
"match"
|
||||||
|
"else"
|
||||||
|
] @keyword
|
||||||
|
|
||||||
|
[
|
||||||
|
"::"
|
||||||
|
"="
|
||||||
|
"+="
|
||||||
|
"-="
|
||||||
|
"*="
|
||||||
|
"/="
|
||||||
|
"=="
|
||||||
|
"!="
|
||||||
|
"<"
|
||||||
|
"<="
|
||||||
|
">"
|
||||||
|
">="
|
||||||
|
"+"
|
||||||
|
"-"
|
||||||
|
"*"
|
||||||
|
"/"
|
||||||
|
"!"
|
||||||
|
"&"
|
||||||
|
"?"
|
||||||
|
"^"
|
||||||
|
".."
|
||||||
|
"..="
|
||||||
|
"|"
|
||||||
|
] @operator
|
||||||
|
|
||||||
|
[
|
||||||
|
"("
|
||||||
|
")"
|
||||||
|
"["
|
||||||
|
"]"
|
||||||
|
"{"
|
||||||
|
"}"
|
||||||
|
] @punctuation.bracket
|
||||||
|
|
||||||
|
[
|
||||||
|
","
|
||||||
|
"."
|
||||||
|
":"
|
||||||
|
";"
|
||||||
|
] @punctuation.delimiter
|
||||||
@@ -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)),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "tree-sitter-brolang",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"generate": "tree-sitter generate",
|
||||||
|
"test": "tree-sitter test"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
(comment) @comment
|
||||||
|
|
||||||
|
[
|
||||||
|
(string)
|
||||||
|
(multiline_string)
|
||||||
|
] @string
|
||||||
|
|
||||||
|
(character) @string
|
||||||
|
(escape_sequence) @escape
|
||||||
|
|
||||||
|
[
|
||||||
|
(integer)
|
||||||
|
(float)
|
||||||
|
] @number
|
||||||
|
|
||||||
|
(boolean) @constant.builtin
|
||||||
|
|
||||||
|
[
|
||||||
|
(none)
|
||||||
|
(undefined)
|
||||||
|
] @constant.builtin
|
||||||
|
|
||||||
|
(builtin_type) @type.builtin
|
||||||
|
(named_type) @type
|
||||||
|
|
||||||
|
(type_declaration name: (identifier) @type)
|
||||||
|
(function_declaration name: (identifier) @function)
|
||||||
|
(parameter name: (identifier) @variable.parameter)
|
||||||
|
|
||||||
|
(call_expression function: (expression (identifier) @function))
|
||||||
|
(call_expression function: (expression (field_expression field: (identifier) @function)))
|
||||||
|
(field_expression field: (identifier) @property)
|
||||||
|
(field_initializer name: (identifier) @property)
|
||||||
|
(keyed_field_initializer name: (identifier) @property)
|
||||||
|
(record_field name: (identifier) @property)
|
||||||
|
(enum_member name: (identifier) @property)
|
||||||
|
(enum_literal name: (identifier) @property)
|
||||||
|
|
||||||
|
(import_declaration alias: (identifier) @module)
|
||||||
|
(opaque_type) @keyword
|
||||||
|
|
||||||
|
[
|
||||||
|
"func"
|
||||||
|
"c_func"
|
||||||
|
"struct"
|
||||||
|
"c_struct"
|
||||||
|
"union"
|
||||||
|
"enum"
|
||||||
|
"distinct"
|
||||||
|
"alias"
|
||||||
|
"import"
|
||||||
|
"return"
|
||||||
|
"try"
|
||||||
|
"catch"
|
||||||
|
"mut"
|
||||||
|
"orelse"
|
||||||
|
"and"
|
||||||
|
"or"
|
||||||
|
"if"
|
||||||
|
"while"
|
||||||
|
"for"
|
||||||
|
"break"
|
||||||
|
"continue"
|
||||||
|
"defer"
|
||||||
|
"yield"
|
||||||
|
"match"
|
||||||
|
"else"
|
||||||
|
] @keyword
|
||||||
|
|
||||||
|
[
|
||||||
|
"::"
|
||||||
|
"="
|
||||||
|
"+="
|
||||||
|
"-="
|
||||||
|
"*="
|
||||||
|
"/="
|
||||||
|
"=="
|
||||||
|
"!="
|
||||||
|
"<"
|
||||||
|
"<="
|
||||||
|
">"
|
||||||
|
">="
|
||||||
|
"+"
|
||||||
|
"-"
|
||||||
|
"*"
|
||||||
|
"/"
|
||||||
|
"!"
|
||||||
|
"&"
|
||||||
|
"?"
|
||||||
|
"^"
|
||||||
|
".."
|
||||||
|
"..="
|
||||||
|
"|"
|
||||||
|
] @operator
|
||||||
|
|
||||||
|
[
|
||||||
|
"("
|
||||||
|
")"
|
||||||
|
"["
|
||||||
|
"]"
|
||||||
|
"{"
|
||||||
|
"}"
|
||||||
|
] @punctuation.bracket
|
||||||
|
|
||||||
|
[
|
||||||
|
","
|
||||||
|
"."
|
||||||
|
":"
|
||||||
|
";"
|
||||||
|
] @punctuation.delimiter
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,54 @@
|
|||||||
|
#ifndef TREE_SITTER_ALLOC_H_
|
||||||
|
#define TREE_SITTER_ALLOC_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
// Allow clients to override allocation functions
|
||||||
|
#ifdef TREE_SITTER_REUSE_ALLOCATOR
|
||||||
|
|
||||||
|
extern void *(*ts_current_malloc)(size_t size);
|
||||||
|
extern void *(*ts_current_calloc)(size_t count, size_t size);
|
||||||
|
extern void *(*ts_current_realloc)(void *ptr, size_t size);
|
||||||
|
extern void (*ts_current_free)(void *ptr);
|
||||||
|
|
||||||
|
#ifndef ts_malloc
|
||||||
|
#define ts_malloc ts_current_malloc
|
||||||
|
#endif
|
||||||
|
#ifndef ts_calloc
|
||||||
|
#define ts_calloc ts_current_calloc
|
||||||
|
#endif
|
||||||
|
#ifndef ts_realloc
|
||||||
|
#define ts_realloc ts_current_realloc
|
||||||
|
#endif
|
||||||
|
#ifndef ts_free
|
||||||
|
#define ts_free ts_current_free
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifndef ts_malloc
|
||||||
|
#define ts_malloc malloc
|
||||||
|
#endif
|
||||||
|
#ifndef ts_calloc
|
||||||
|
#define ts_calloc calloc
|
||||||
|
#endif
|
||||||
|
#ifndef ts_realloc
|
||||||
|
#define ts_realloc realloc
|
||||||
|
#endif
|
||||||
|
#ifndef ts_free
|
||||||
|
#define ts_free free
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TREE_SITTER_ALLOC_H_
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
#ifndef TREE_SITTER_ARRAY_H_
|
||||||
|
#define TREE_SITTER_ARRAY_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "./alloc.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4101)
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Array(T) \
|
||||||
|
struct { \
|
||||||
|
T *contents; \
|
||||||
|
uint32_t size; \
|
||||||
|
uint32_t capacity; \
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize an array.
|
||||||
|
#define array_init(self) \
|
||||||
|
((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)
|
||||||
|
|
||||||
|
/// Create an empty array.
|
||||||
|
#define array_new() \
|
||||||
|
{ NULL, 0, 0 }
|
||||||
|
|
||||||
|
/// Get a pointer to the element at a given `index` in the array.
|
||||||
|
#define array_get(self, _index) \
|
||||||
|
(assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index])
|
||||||
|
|
||||||
|
/// Get a pointer to the first element in the array.
|
||||||
|
#define array_front(self) array_get(self, 0)
|
||||||
|
|
||||||
|
/// Get a pointer to the last element in the array.
|
||||||
|
#define array_back(self) array_get(self, (self)->size - 1)
|
||||||
|
|
||||||
|
/// Clear the array, setting its size to zero. Note that this does not free any
|
||||||
|
/// memory allocated for the array's contents.
|
||||||
|
#define array_clear(self) ((self)->size = 0)
|
||||||
|
|
||||||
|
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
|
||||||
|
/// less than the array's current capacity, this function has no effect.
|
||||||
|
#define array_reserve(self, new_capacity) \
|
||||||
|
((self)->contents = _array__reserve( \
|
||||||
|
(void *)(self)->contents, &(self)->capacity, \
|
||||||
|
array_elem_size(self), new_capacity) \
|
||||||
|
)
|
||||||
|
|
||||||
|
/// Free any memory allocated for this array. Note that this does not free any
|
||||||
|
/// memory allocated for the array's contents.
|
||||||
|
#define array_delete(self) _array__delete((self), (void *)(self)->contents, sizeof(*self))
|
||||||
|
|
||||||
|
/// Push a new `element` onto the end of the array.
|
||||||
|
#define array_push(self, element) \
|
||||||
|
do { \
|
||||||
|
(self)->contents = _array__grow( \
|
||||||
|
(void *)(self)->contents, (self)->size, &(self)->capacity, \
|
||||||
|
1, array_elem_size(self) \
|
||||||
|
); \
|
||||||
|
(self)->contents[(self)->size++] = (element); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
/// Increase the array's size by `count` elements.
|
||||||
|
/// New elements are zero-initialized.
|
||||||
|
#define array_grow_by(self, count) \
|
||||||
|
do { \
|
||||||
|
if ((count) == 0) break; \
|
||||||
|
(self)->contents = _array__grow( \
|
||||||
|
(self)->contents, (self)->size, &(self)->capacity, \
|
||||||
|
count, array_elem_size(self) \
|
||||||
|
); \
|
||||||
|
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
|
||||||
|
(self)->size += (count); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/// Append all elements from one array to the end of another.
|
||||||
|
#define array_push_all(self, other) \
|
||||||
|
array_extend((self), (other)->size, (other)->contents)
|
||||||
|
|
||||||
|
/// Append `count` elements to the end of the array, reading their values from the
|
||||||
|
/// `contents` pointer.
|
||||||
|
#define array_extend(self, count, other_contents) \
|
||||||
|
(self)->contents = _array__splice( \
|
||||||
|
(void*)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||||
|
array_elem_size(self), (self)->size, 0, count, other_contents \
|
||||||
|
)
|
||||||
|
|
||||||
|
/// Remove `old_count` elements from the array starting at the given `index`. At
|
||||||
|
/// the same index, insert `new_count` new elements, reading their values from the
|
||||||
|
/// `new_contents` pointer.
|
||||||
|
#define array_splice(self, _index, old_count, new_count, new_contents) \
|
||||||
|
(self)->contents = _array__splice( \
|
||||||
|
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||||
|
array_elem_size(self), _index, old_count, new_count, new_contents \
|
||||||
|
)
|
||||||
|
|
||||||
|
/// Insert one `element` into the array at the given `index`.
|
||||||
|
#define array_insert(self, _index, element) \
|
||||||
|
(self)->contents = _array__splice( \
|
||||||
|
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||||
|
array_elem_size(self), _index, 0, 1, &(element) \
|
||||||
|
)
|
||||||
|
|
||||||
|
/// Remove one element from the array at the given `index`.
|
||||||
|
#define array_erase(self, _index) \
|
||||||
|
_array__erase((void *)(self)->contents, &(self)->size, array_elem_size(self), _index)
|
||||||
|
|
||||||
|
/// Pop the last element off the array, returning the element by value.
|
||||||
|
#define array_pop(self) ((self)->contents[--(self)->size])
|
||||||
|
|
||||||
|
/// Assign the contents of one array to another, reallocating if necessary.
|
||||||
|
#define array_assign(self, other) \
|
||||||
|
(self)->contents = _array__assign( \
|
||||||
|
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||||
|
(const void *)(other)->contents, (other)->size, array_elem_size(self) \
|
||||||
|
)
|
||||||
|
|
||||||
|
/// Swap one array with another
|
||||||
|
#define array_swap(self, other) \
|
||||||
|
do { \
|
||||||
|
struct Swap swapped_contents = _array__swap( \
|
||||||
|
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
|
||||||
|
(void *)(other)->contents, &(other)->size, &(other)->capacity \
|
||||||
|
); \
|
||||||
|
(self)->contents = swapped_contents.self_contents; \
|
||||||
|
(other)->contents = swapped_contents.other_contents; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/// Get the size of the array contents
|
||||||
|
#define array_elem_size(self) (sizeof *(self)->contents)
|
||||||
|
|
||||||
|
/// Search a sorted array for a given `needle` value, using the given `compare`
|
||||||
|
/// callback to determine the order.
|
||||||
|
///
|
||||||
|
/// If an existing element is found to be equal to `needle`, then the `index`
|
||||||
|
/// out-parameter is set to the existing value's index, and the `exists`
|
||||||
|
/// out-parameter is set to true. Otherwise, `index` is set to an index where
|
||||||
|
/// `needle` should be inserted in order to preserve the sorting, and `exists`
|
||||||
|
/// is set to false.
|
||||||
|
#define array_search_sorted_with(self, compare, needle, _index, _exists) \
|
||||||
|
_array__search_sorted(self, 0, compare, , needle, _index, _exists)
|
||||||
|
|
||||||
|
/// Search a sorted array for a given `needle` value, using integer comparisons
|
||||||
|
/// of a given struct field (specified with a leading dot) to determine the order.
|
||||||
|
///
|
||||||
|
/// See also `array_search_sorted_with`.
|
||||||
|
#define array_search_sorted_by(self, field, needle, _index, _exists) \
|
||||||
|
_array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists)
|
||||||
|
|
||||||
|
/// Insert a given `value` into a sorted array, using the given `compare`
|
||||||
|
/// callback to determine the order.
|
||||||
|
#define array_insert_sorted_with(self, compare, value) \
|
||||||
|
do { \
|
||||||
|
unsigned _index, _exists; \
|
||||||
|
array_search_sorted_with(self, compare, &(value), &_index, &_exists); \
|
||||||
|
if (!_exists) array_insert(self, _index, value); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/// Insert a given `value` into a sorted array, using integer comparisons of
|
||||||
|
/// a given struct field (specified with a leading dot) to determine the order.
|
||||||
|
///
|
||||||
|
/// See also `array_search_sorted_by`.
|
||||||
|
#define array_insert_sorted_by(self, field, value) \
|
||||||
|
do { \
|
||||||
|
unsigned _index, _exists; \
|
||||||
|
array_search_sorted_by(self, field, (value) field, &_index, &_exists); \
|
||||||
|
if (!_exists) array_insert(self, _index, value); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// Private
|
||||||
|
|
||||||
|
// Pointers to individual `Array` fields (rather than the entire `Array` itself)
|
||||||
|
// are passed to the various `_array__*` functions below to address strict aliasing
|
||||||
|
// violations that arises when the _entire_ `Array` struct is passed as `Array(void)*`.
|
||||||
|
//
|
||||||
|
// The `Array` type itself was not altered as a solution in order to avoid breakage
|
||||||
|
// with existing consumers (in particular, parsers with external scanners).
|
||||||
|
|
||||||
|
/// This is not what you're looking for, see `array_delete`.
|
||||||
|
static inline void _array__delete(void *self, void *contents, size_t self_size) {
|
||||||
|
if (contents) ts_free(contents);
|
||||||
|
if (self) memset(self, 0, self_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is not what you're looking for, see `array_erase`.
|
||||||
|
static inline void _array__erase(void* self_contents, uint32_t *size,
|
||||||
|
size_t element_size, uint32_t index) {
|
||||||
|
assert(index < *size);
|
||||||
|
char *contents = (char *)self_contents;
|
||||||
|
memmove(contents + index * element_size, contents + (index + 1) * element_size,
|
||||||
|
(*size - index - 1) * element_size);
|
||||||
|
(*size)--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is not what you're looking for, see `array_reserve`.
|
||||||
|
static inline void *_array__reserve(void *contents, uint32_t *capacity,
|
||||||
|
size_t element_size, uint32_t new_capacity) {
|
||||||
|
void *new_contents = contents;
|
||||||
|
if (new_capacity > *capacity) {
|
||||||
|
if (contents) {
|
||||||
|
new_contents = ts_realloc(contents, new_capacity * element_size);
|
||||||
|
} else {
|
||||||
|
new_contents = ts_malloc(new_capacity * element_size);
|
||||||
|
}
|
||||||
|
*capacity = new_capacity;
|
||||||
|
}
|
||||||
|
return new_contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is not what you're looking for, see `array_assign`.
|
||||||
|
static inline void *_array__assign(void* self_contents, uint32_t *self_size, uint32_t *self_capacity,
|
||||||
|
const void *other_contents, uint32_t other_size, size_t element_size) {
|
||||||
|
void *new_contents = _array__reserve(self_contents, self_capacity, element_size, other_size);
|
||||||
|
*self_size = other_size;
|
||||||
|
memcpy(new_contents, other_contents, *self_size * element_size);
|
||||||
|
return new_contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Swap {
|
||||||
|
void *self_contents;
|
||||||
|
void *other_contents;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// This is not what you're looking for, see `array_swap`.
|
||||||
|
// static inline void _array__swap(Array *self, Array *other) {
|
||||||
|
static inline struct Swap _array__swap(void *self_contents, uint32_t *self_size, uint32_t *self_capacity,
|
||||||
|
void *other_contents, uint32_t *other_size, uint32_t *other_capacity) {
|
||||||
|
void *new_self_contents = other_contents;
|
||||||
|
uint32_t new_self_size = *other_size;
|
||||||
|
uint32_t new_self_capacity = *other_capacity;
|
||||||
|
|
||||||
|
void *new_other_contents = self_contents;
|
||||||
|
*other_size = *self_size;
|
||||||
|
*other_capacity = *self_capacity;
|
||||||
|
|
||||||
|
*self_size = new_self_size;
|
||||||
|
*self_capacity = new_self_capacity;
|
||||||
|
|
||||||
|
struct Swap out = {
|
||||||
|
.self_contents = new_self_contents,
|
||||||
|
.other_contents = new_other_contents,
|
||||||
|
};
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
|
||||||
|
static inline void *_array__grow(void *contents, uint32_t size, uint32_t *capacity,
|
||||||
|
uint32_t count, size_t element_size) {
|
||||||
|
void *new_contents = contents;
|
||||||
|
uint32_t new_size = size + count;
|
||||||
|
if (new_size > *capacity) {
|
||||||
|
uint32_t new_capacity = *capacity * 2;
|
||||||
|
if (new_capacity < 8) new_capacity = 8;
|
||||||
|
if (new_capacity < new_size) new_capacity = new_size;
|
||||||
|
new_contents = _array__reserve(contents, capacity, element_size, new_capacity);
|
||||||
|
}
|
||||||
|
return new_contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is not what you're looking for, see `array_splice`.
|
||||||
|
static inline void *_array__splice(void *self_contents, uint32_t *size, uint32_t *capacity,
|
||||||
|
size_t element_size,
|
||||||
|
uint32_t index, uint32_t old_count,
|
||||||
|
uint32_t new_count, const void *elements) {
|
||||||
|
uint32_t new_size = *size + new_count - old_count;
|
||||||
|
uint32_t old_end = index + old_count;
|
||||||
|
uint32_t new_end = index + new_count;
|
||||||
|
assert(old_end <= *size);
|
||||||
|
|
||||||
|
void *new_contents = _array__reserve(self_contents, capacity, element_size, new_size);
|
||||||
|
|
||||||
|
char *contents = (char *)new_contents;
|
||||||
|
if (*size > old_end) {
|
||||||
|
memmove(
|
||||||
|
contents + new_end * element_size,
|
||||||
|
contents + old_end * element_size,
|
||||||
|
(*size - old_end) * element_size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (new_count > 0) {
|
||||||
|
if (elements) {
|
||||||
|
memcpy(
|
||||||
|
(contents + index * element_size),
|
||||||
|
elements,
|
||||||
|
new_count * element_size
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
memset(
|
||||||
|
(contents + index * element_size),
|
||||||
|
0,
|
||||||
|
new_count * element_size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*size += new_count - old_count;
|
||||||
|
|
||||||
|
return new_contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
|
||||||
|
/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`.
|
||||||
|
#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \
|
||||||
|
do { \
|
||||||
|
*(_index) = start; \
|
||||||
|
*(_exists) = false; \
|
||||||
|
uint32_t size = (self)->size - *(_index); \
|
||||||
|
if (size == 0) break; \
|
||||||
|
int comparison; \
|
||||||
|
while (size > 1) { \
|
||||||
|
uint32_t half_size = size / 2; \
|
||||||
|
uint32_t mid_index = *(_index) + half_size; \
|
||||||
|
comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
|
||||||
|
if (comparison <= 0) *(_index) = mid_index; \
|
||||||
|
size -= half_size; \
|
||||||
|
} \
|
||||||
|
comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \
|
||||||
|
if (comparison == 0) *(_exists) = true; \
|
||||||
|
else if (comparison < 0) *(_index) += 1; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/// Helper macro for the `_sorted_by` routines below. This takes the left (existing)
|
||||||
|
/// parameter by reference in order to work with the generic sorting function above.
|
||||||
|
#define _compare_int(a, b) ((int)*(a) - (int)(b))
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#elif defined(__GNUC__) || defined(__clang__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TREE_SITTER_ARRAY_H_
|
||||||
@@ -0,0 +1,286 @@
|
|||||||
|
#ifndef TREE_SITTER_PARSER_H_
|
||||||
|
#define TREE_SITTER_PARSER_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define ts_builtin_sym_error ((TSSymbol)-1)
|
||||||
|
#define ts_builtin_sym_end 0
|
||||||
|
#define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
#ifndef TREE_SITTER_API_H_
|
||||||
|
typedef uint16_t TSStateId;
|
||||||
|
typedef uint16_t TSSymbol;
|
||||||
|
typedef uint16_t TSFieldId;
|
||||||
|
typedef struct TSLanguage TSLanguage;
|
||||||
|
typedef struct TSLanguageMetadata {
|
||||||
|
uint8_t major_version;
|
||||||
|
uint8_t minor_version;
|
||||||
|
uint8_t patch_version;
|
||||||
|
} TSLanguageMetadata;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TSFieldId field_id;
|
||||||
|
uint8_t child_index;
|
||||||
|
bool inherited;
|
||||||
|
} TSFieldMapEntry;
|
||||||
|
|
||||||
|
// Used to index the field and supertype maps.
|
||||||
|
typedef struct {
|
||||||
|
uint16_t index;
|
||||||
|
uint16_t length;
|
||||||
|
} TSMapSlice;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool visible;
|
||||||
|
bool named;
|
||||||
|
bool supertype;
|
||||||
|
} TSSymbolMetadata;
|
||||||
|
|
||||||
|
typedef struct TSLexer TSLexer;
|
||||||
|
|
||||||
|
struct TSLexer {
|
||||||
|
int32_t lookahead;
|
||||||
|
TSSymbol result_symbol;
|
||||||
|
void (*advance)(TSLexer *, bool);
|
||||||
|
void (*mark_end)(TSLexer *);
|
||||||
|
uint32_t (*get_column)(TSLexer *);
|
||||||
|
bool (*is_at_included_range_start)(const TSLexer *);
|
||||||
|
bool (*eof)(const TSLexer *);
|
||||||
|
void (*log)(const TSLexer *, const char *, ...);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TSParseActionTypeShift,
|
||||||
|
TSParseActionTypeReduce,
|
||||||
|
TSParseActionTypeAccept,
|
||||||
|
TSParseActionTypeRecover,
|
||||||
|
} TSParseActionType;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
uint8_t type;
|
||||||
|
TSStateId state;
|
||||||
|
bool extra;
|
||||||
|
bool repetition;
|
||||||
|
} shift;
|
||||||
|
struct {
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t child_count;
|
||||||
|
TSSymbol symbol;
|
||||||
|
int16_t dynamic_precedence;
|
||||||
|
uint16_t production_id;
|
||||||
|
} reduce;
|
||||||
|
uint8_t type;
|
||||||
|
} TSParseAction;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t lex_state;
|
||||||
|
uint16_t external_lex_state;
|
||||||
|
} TSLexMode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t lex_state;
|
||||||
|
uint16_t external_lex_state;
|
||||||
|
uint16_t reserved_word_set_id;
|
||||||
|
} TSLexerMode;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
TSParseAction action;
|
||||||
|
struct {
|
||||||
|
uint8_t count;
|
||||||
|
bool reusable;
|
||||||
|
} entry;
|
||||||
|
} TSParseActionEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t start;
|
||||||
|
int32_t end;
|
||||||
|
} TSCharacterRange;
|
||||||
|
|
||||||
|
struct TSLanguage {
|
||||||
|
uint32_t abi_version;
|
||||||
|
uint32_t symbol_count;
|
||||||
|
uint32_t alias_count;
|
||||||
|
uint32_t token_count;
|
||||||
|
uint32_t external_token_count;
|
||||||
|
uint32_t state_count;
|
||||||
|
uint32_t large_state_count;
|
||||||
|
uint32_t production_id_count;
|
||||||
|
uint32_t field_count;
|
||||||
|
uint16_t max_alias_sequence_length;
|
||||||
|
const uint16_t *parse_table;
|
||||||
|
const uint16_t *small_parse_table;
|
||||||
|
const uint32_t *small_parse_table_map;
|
||||||
|
const TSParseActionEntry *parse_actions;
|
||||||
|
const char * const *symbol_names;
|
||||||
|
const char * const *field_names;
|
||||||
|
const TSMapSlice *field_map_slices;
|
||||||
|
const TSFieldMapEntry *field_map_entries;
|
||||||
|
const TSSymbolMetadata *symbol_metadata;
|
||||||
|
const TSSymbol *public_symbol_map;
|
||||||
|
const uint16_t *alias_map;
|
||||||
|
const TSSymbol *alias_sequences;
|
||||||
|
const TSLexerMode *lex_modes;
|
||||||
|
bool (*lex_fn)(TSLexer *, TSStateId);
|
||||||
|
bool (*keyword_lex_fn)(TSLexer *, TSStateId);
|
||||||
|
TSSymbol keyword_capture_token;
|
||||||
|
struct {
|
||||||
|
const bool *states;
|
||||||
|
const TSSymbol *symbol_map;
|
||||||
|
void *(*create)(void);
|
||||||
|
void (*destroy)(void *);
|
||||||
|
bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist);
|
||||||
|
unsigned (*serialize)(void *, char *);
|
||||||
|
void (*deserialize)(void *, const char *, unsigned);
|
||||||
|
} external_scanner;
|
||||||
|
const TSStateId *primary_state_ids;
|
||||||
|
const char *name;
|
||||||
|
const TSSymbol *reserved_words;
|
||||||
|
uint16_t max_reserved_word_set_size;
|
||||||
|
uint32_t supertype_count;
|
||||||
|
const TSSymbol *supertype_symbols;
|
||||||
|
const TSMapSlice *supertype_map_slices;
|
||||||
|
const TSSymbol *supertype_map_entries;
|
||||||
|
TSLanguageMetadata metadata;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) {
|
||||||
|
uint32_t index = 0;
|
||||||
|
uint32_t size = len - index;
|
||||||
|
while (size > 1) {
|
||||||
|
uint32_t half_size = size / 2;
|
||||||
|
uint32_t mid_index = index + half_size;
|
||||||
|
const TSCharacterRange *range = &ranges[mid_index];
|
||||||
|
if (lookahead >= range->start && lookahead <= range->end) {
|
||||||
|
return true;
|
||||||
|
} else if (lookahead > range->end) {
|
||||||
|
index = mid_index;
|
||||||
|
}
|
||||||
|
size -= half_size;
|
||||||
|
}
|
||||||
|
const TSCharacterRange *range = &ranges[index];
|
||||||
|
return (lookahead >= range->start && lookahead <= range->end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lexer Macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define UNUSED __pragma(warning(suppress : 4101))
|
||||||
|
#else
|
||||||
|
#define UNUSED __attribute__((unused))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define START_LEXER() \
|
||||||
|
bool result = false; \
|
||||||
|
bool skip = false; \
|
||||||
|
UNUSED \
|
||||||
|
bool eof = false; \
|
||||||
|
int32_t lookahead; \
|
||||||
|
goto start; \
|
||||||
|
next_state: \
|
||||||
|
lexer->advance(lexer, skip); \
|
||||||
|
start: \
|
||||||
|
skip = false; \
|
||||||
|
lookahead = lexer->lookahead;
|
||||||
|
|
||||||
|
#define ADVANCE(state_value) \
|
||||||
|
{ \
|
||||||
|
state = state_value; \
|
||||||
|
goto next_state; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADVANCE_MAP(...) \
|
||||||
|
{ \
|
||||||
|
static const uint16_t map[] = { __VA_ARGS__ }; \
|
||||||
|
for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \
|
||||||
|
if (map[i] == lookahead) { \
|
||||||
|
state = map[i + 1]; \
|
||||||
|
goto next_state; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SKIP(state_value) \
|
||||||
|
{ \
|
||||||
|
skip = true; \
|
||||||
|
state = state_value; \
|
||||||
|
goto next_state; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ACCEPT_TOKEN(symbol_value) \
|
||||||
|
result = true; \
|
||||||
|
lexer->result_symbol = symbol_value; \
|
||||||
|
lexer->mark_end(lexer);
|
||||||
|
|
||||||
|
#define END_STATE() return result;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse Table Macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT)
|
||||||
|
|
||||||
|
#define STATE(id) id
|
||||||
|
|
||||||
|
#define ACTIONS(id) id
|
||||||
|
|
||||||
|
#define SHIFT(state_value) \
|
||||||
|
{{ \
|
||||||
|
.shift = { \
|
||||||
|
.type = TSParseActionTypeShift, \
|
||||||
|
.state = (state_value) \
|
||||||
|
} \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#define SHIFT_REPEAT(state_value) \
|
||||||
|
{{ \
|
||||||
|
.shift = { \
|
||||||
|
.type = TSParseActionTypeShift, \
|
||||||
|
.state = (state_value), \
|
||||||
|
.repetition = true \
|
||||||
|
} \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#define SHIFT_EXTRA() \
|
||||||
|
{{ \
|
||||||
|
.shift = { \
|
||||||
|
.type = TSParseActionTypeShift, \
|
||||||
|
.extra = true \
|
||||||
|
} \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#define REDUCE(symbol_name, children, precedence, prod_id) \
|
||||||
|
{{ \
|
||||||
|
.reduce = { \
|
||||||
|
.type = TSParseActionTypeReduce, \
|
||||||
|
.symbol = symbol_name, \
|
||||||
|
.child_count = children, \
|
||||||
|
.dynamic_precedence = precedence, \
|
||||||
|
.production_id = prod_id \
|
||||||
|
}, \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#define RECOVER() \
|
||||||
|
{{ \
|
||||||
|
.type = TSParseActionTypeRecover \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#define ACCEPT_INPUT() \
|
||||||
|
{{ \
|
||||||
|
.type = TSParseActionTypeAccept \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TREE_SITTER_PARSER_H_
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
==================
|
||||||
|
Core syntax
|
||||||
|
==================
|
||||||
|
|
||||||
|
io :: import "@std/io"
|
||||||
|
|
||||||
|
Status :: enum {
|
||||||
|
ok
|
||||||
|
bad
|
||||||
|
}
|
||||||
|
|
||||||
|
Pair :: struct {
|
||||||
|
left i32
|
||||||
|
right i32
|
||||||
|
}
|
||||||
|
|
||||||
|
sum func(a, b i32) i32 ! Status {
|
||||||
|
result :: a + b
|
||||||
|
if result > 0 {
|
||||||
|
return result
|
||||||
|
} else {
|
||||||
|
return .bad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
(source_file
|
||||||
|
(import_declaration
|
||||||
|
(identifier)
|
||||||
|
(string
|
||||||
|
(string_content)))
|
||||||
|
(type_declaration
|
||||||
|
(identifier)
|
||||||
|
(enum_type
|
||||||
|
(enum_body
|
||||||
|
(enum_member
|
||||||
|
(identifier))
|
||||||
|
(enum_member
|
||||||
|
(identifier)))))
|
||||||
|
(type_declaration
|
||||||
|
(identifier)
|
||||||
|
(struct_type
|
||||||
|
(record_body
|
||||||
|
(record_field
|
||||||
|
(identifier)
|
||||||
|
(type
|
||||||
|
(builtin_type)))
|
||||||
|
(record_field
|
||||||
|
(identifier)
|
||||||
|
(type
|
||||||
|
(builtin_type))))))
|
||||||
|
(function_declaration
|
||||||
|
(identifier)
|
||||||
|
(parameter_list
|
||||||
|
(parameter
|
||||||
|
(identifier)
|
||||||
|
(identifier)
|
||||||
|
(type
|
||||||
|
(builtin_type))))
|
||||||
|
(type
|
||||||
|
(builtin_type))
|
||||||
|
(type
|
||||||
|
(named_type
|
||||||
|
(qualified_identifier
|
||||||
|
(identifier))))
|
||||||
|
(block
|
||||||
|
(statement
|
||||||
|
(constant_declaration
|
||||||
|
(identifier)
|
||||||
|
(expression
|
||||||
|
(binary_expression
|
||||||
|
(expression
|
||||||
|
(identifier))
|
||||||
|
(expression
|
||||||
|
(identifier))))))
|
||||||
|
(statement
|
||||||
|
(if_statement
|
||||||
|
(expression
|
||||||
|
(binary_expression
|
||||||
|
(expression
|
||||||
|
(identifier))
|
||||||
|
(expression
|
||||||
|
(integer))))
|
||||||
|
(statement
|
||||||
|
(block
|
||||||
|
(statement
|
||||||
|
(return_statement
|
||||||
|
(expression
|
||||||
|
(identifier))))))
|
||||||
|
(statement
|
||||||
|
(block
|
||||||
|
(statement
|
||||||
|
(return_statement
|
||||||
|
(expression
|
||||||
|
(enum_literal
|
||||||
|
(identifier))))))))))))
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"grammars": [
|
||||||
|
{
|
||||||
|
"name": "brolang",
|
||||||
|
"camelcase": "Brolang",
|
||||||
|
"scope": "source.bro",
|
||||||
|
"path": ".",
|
||||||
|
"file-types": ["bro", "hon"],
|
||||||
|
"highlights": "queries/highlights.scm"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Tree-sitter grammar for Brolang",
|
||||||
|
"authors": [{"name": "Brolang contributors"}]
|
||||||
|
},
|
||||||
|
"bindings": {
|
||||||
|
"c": false,
|
||||||
|
"go": false,
|
||||||
|
"java": false,
|
||||||
|
"node": false,
|
||||||
|
"python": false,
|
||||||
|
"rust": false,
|
||||||
|
"swift": false,
|
||||||
|
"zig": false
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user