wip tree-sitter
This commit is contained in:
241
tree-sitter/grammar.js
Normal file
241
tree-sitter/grammar.js
Normal file
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* @file Parser for the Crepuscular(ray) functional programming language
|
||||
* @author Alexander Nutz <alexander.nutz@vxcc.dev>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/// <reference types="tree-sitter-cli/dsl" />
|
||||
// @ts-check
|
||||
|
||||
module.exports = grammar({
|
||||
name: "crepuscular",
|
||||
|
||||
reserved: {
|
||||
toplevel_kw: $ =>
|
||||
['type', 'with', 'extensible', 'extend', 'union', 'def'],
|
||||
},
|
||||
|
||||
extras: ($) => [
|
||||
/\s/, // whitespace
|
||||
$.comment,
|
||||
],
|
||||
|
||||
word: $ => $._identifier_tok,
|
||||
|
||||
rules: {
|
||||
source_file: $ => repeat($._definition),
|
||||
|
||||
_identifier_tok: $ => token(/[a-zA-Z_]+[a-zA-Z0-9_]*/),
|
||||
identifier: $ => reserved('toplevel_kw', $._identifier_tok),
|
||||
path: $ => prec.left(seq($.identifier, repeat(seq('.', $.identifier)))),
|
||||
|
||||
comment: $ =>
|
||||
token(seq("#", /.*/)),
|
||||
|
||||
_definition: $ => choice(
|
||||
$.full_partial_type_definition,
|
||||
$.type_definition,
|
||||
$.extensible_union,
|
||||
$.extend_decl,
|
||||
$.def,
|
||||
),
|
||||
|
||||
extensible_union: $ => seq(
|
||||
'extensible', 'union', $.path),
|
||||
|
||||
extend_decl: $ => seq(
|
||||
'extend', $.path, 'with', $.tag, $._type),
|
||||
|
||||
full_partial_type_definition: $ => seq(
|
||||
"type",
|
||||
"?", $.path,
|
||||
"=",
|
||||
$._type
|
||||
),
|
||||
|
||||
type_definition: $ => seq(
|
||||
"type",
|
||||
repeat($.identifier),
|
||||
$.path,
|
||||
"=",
|
||||
$._type
|
||||
),
|
||||
|
||||
_type_atom: $ => choice(
|
||||
$.just_type,
|
||||
$.partial_type,
|
||||
seq('(', $._type, ')'),
|
||||
$.record_type,
|
||||
),
|
||||
|
||||
_type_non_fn: $ => choice(
|
||||
$._type_atom,
|
||||
$.tagged_type,
|
||||
$.union_type,
|
||||
$.partial_union_type,
|
||||
$.parametrized_type,
|
||||
$.with_type,
|
||||
$.recursive_type,
|
||||
),
|
||||
|
||||
_type: $ => choice(
|
||||
$._type_non_fn,
|
||||
$.fn_type,
|
||||
),
|
||||
|
||||
union_type: $ => prec.left(1,
|
||||
seq($._type, '|', $._type)),
|
||||
|
||||
partial_union_type: $ => prec.left(1,
|
||||
seq($._type, '|', '...', $.partial_type)),
|
||||
|
||||
tag: $ => new RustRegex("'(?:[a-zA-Z_][a-zA-Z0-9_]*(?:[.][a-zA-Z_0-9]+)*)"),
|
||||
tagged_type: $ => prec.right(3,
|
||||
seq($.tag, optional(
|
||||
choice(
|
||||
$._type_atom,
|
||||
$.parametrized_type)))),
|
||||
|
||||
multi_type_parameters: $ => seq('[', $._type, repeat(seq(',', $._type)), ']'),
|
||||
parametrized_type: $ => prec.left(4, seq(
|
||||
choice(
|
||||
$.multi_type_parameters,
|
||||
$._type_atom
|
||||
),
|
||||
repeat1($.path)
|
||||
)),
|
||||
|
||||
with_type: $ => seq('with', $.identifier, repeat(seq(',', $.identifier)), ':', $._type),
|
||||
|
||||
recursive_type: $ => seq('&', $.identifier, $._type),
|
||||
|
||||
partial_type: $ => seq('?', $.identifier),
|
||||
|
||||
fn_type: $ => prec.left(-10,
|
||||
seq($._type, '->', $._type)),
|
||||
|
||||
just_type: $ => prec(-1, $.path),
|
||||
|
||||
record_type_field: $ => seq($.identifier, ':', $._type),
|
||||
record_type: $ => seq(
|
||||
'{',
|
||||
repeat(seq($.record_type_field, ',')),
|
||||
optional(choice(
|
||||
$.record_type_field,
|
||||
seq('...', $.partial_type),
|
||||
)),
|
||||
'}'),
|
||||
|
||||
escape_sequence: $ =>
|
||||
token.immediate(
|
||||
seq('\\', /[tbrnf0"'\\]/)),
|
||||
|
||||
char_middle: $ => /./,
|
||||
string_middle: $ => /[^\\"]+/,
|
||||
|
||||
char_literal: $ =>
|
||||
seq('\'', choice($.escape_sequence, $.char_middle), '\''),
|
||||
|
||||
string_literal: $ =>
|
||||
seq('"', repeat(choice($.escape_sequence, $.string_middle)), '"'),
|
||||
|
||||
num_literal: $ =>
|
||||
seq(
|
||||
choice(
|
||||
/[0-9]+/,
|
||||
/\-[0-9]+/
|
||||
),
|
||||
optional(token.immediate(/[.][0-9]+/))
|
||||
),
|
||||
|
||||
list_expression: $ =>
|
||||
seq(
|
||||
'[',
|
||||
repeat(seq($.expression, ',')),
|
||||
optional($.expression),
|
||||
']'),
|
||||
|
||||
field_access: $ => prec.left(
|
||||
seq($._atom, ':', $.identifier)),
|
||||
|
||||
function_call: $ => prec.left(1,
|
||||
seq($._atom, '(',
|
||||
repeat(seq($.expression, ',')), optional($.expression),
|
||||
')')),
|
||||
|
||||
ident_expr: $ => $.identifier,
|
||||
|
||||
record_expr_field: $ =>
|
||||
seq($.identifier, ':', $.expression),
|
||||
|
||||
record_expr: $ => seq(
|
||||
'{',
|
||||
repeat(seq($.record_expr_field, ',')),
|
||||
optional($.record_expr_field),
|
||||
'}'),
|
||||
|
||||
_atom: $ => choice(
|
||||
prec(0, seq('(', $.expression, ')')),
|
||||
$.ident_expr,
|
||||
$.char_literal,
|
||||
$.string_literal,
|
||||
$.num_literal,
|
||||
$.list_expression,
|
||||
$.field_access,
|
||||
$.function_call,
|
||||
$.record_expr,
|
||||
// TODO
|
||||
),
|
||||
|
||||
let_binding: $ => seq(
|
||||
'let',
|
||||
$.identifier,
|
||||
'=',
|
||||
$.expression,
|
||||
optional('in'),
|
||||
$.expression,
|
||||
),
|
||||
|
||||
await_binding: $ => seq(
|
||||
'await',
|
||||
$.identifier,
|
||||
'=',
|
||||
$.expression,
|
||||
optional('in'),
|
||||
$.expression,
|
||||
),
|
||||
|
||||
type_downcast: $ => seq(
|
||||
$._atom,
|
||||
'::',
|
||||
$._type,
|
||||
),
|
||||
|
||||
lambda: $ => prec.right(4, seq(
|
||||
$.identifier,
|
||||
optional(seq(':', $._type_non_fn)),
|
||||
'->',
|
||||
$.expression
|
||||
)),
|
||||
|
||||
expression: $ => choice(
|
||||
$._atom,
|
||||
$.let_binding,
|
||||
$.await_binding,
|
||||
$.type_downcast,
|
||||
$.lambda,
|
||||
// TODO
|
||||
),
|
||||
|
||||
def: $ => seq(
|
||||
'def', $.path,
|
||||
choice(
|
||||
seq(':', $._type),
|
||||
seq(
|
||||
optional(seq(':', $._type)),
|
||||
seq('=', $.expression),
|
||||
)
|
||||
),
|
||||
),
|
||||
}
|
||||
});
|
Reference in New Issue
Block a user