/
grammar.js
99 lines (98 loc) · 3.12 KB
/
grammar.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
module.exports = grammar({
name: 'clojure',
extras: $ => [/[\s,]/, $.comment],
rules: {
source_file: $ => repeat($._form),
comment: $ => /;.*/,
_form: $ => choice($._non_discard, $.discard),
_non_discard: $ => choice($._literal, $._reader_macro),
discard: $ => seq('#_', optional($.discard), $._non_discard),
_reader_macro: $ => choice(
$.anonymous_function,
$.meta_data,
$.regex,
$.var_quote,
$.set,
$.dispatch,
$.deref,
$.quote,
$.backtick,
$.unquote,
$.unquote_splicing,
$.gensym,
$.reader_conditional,
$.reader_conditional_splicing,
$.host_expression
),
anonymous_function: $ => seq('#(', repeat($._form), ')'),
meta_data: $ => seq(choice('#^', '^'), choice($.map, $.symbol, $.keyword), $._form),
regex: $ => seq('#', $.string),
var_quote: $ => seq('#\'', $.symbol),
set: $ => seq('#{', repeat($._form), '}'),
dispatch: $ => seq('#', $.symbol, $._form),
deref: $ => seq('@', $._form),
quote: $ => seq('\'', $._form),
backtick: $ => seq('`', $._form),
unquote: $ => seq('~', $._form),
unquote_splicing: $ => seq('~@', $._form),
gensym: $ => prec(1, seq($._symbol, '#')),
reader_conditional: $ => seq("#?(", repeat(seq($.keyword, $._form)), ")"),
reader_conditional_splicing: $ => seq("#?@(", repeat(seq($.keyword, $._form)), ")"),
host_expression: $ => seq('#+', $._form, $._form),
escape_sequence: $ => token.immediate(seq(
'\\',
choice(
/[^xu0-7]/,
/[0-7]{1,3}/,
/x[0-9a-fA-F]{2}/,
/u[0-9a-fA-F]{4}/,
/u{[0-9a-fA-F]+}/
)
)),
string: $ => seq(
'"',
repeat(choice(
token.immediate(/[^"\\]+/),
$.escape_sequence
)),
'"'
),
_literal: $ => choice(
$.number,
$.symbol,
$.string,
$.character,
$.nil,
$.boolean,
$.keyword,
$.list,
$.vector,
$.map
),
_symbol: $ => /((([-+][a-zA-Z.<>$%&=*/+\-!?_'])|([a-zA-Z.<>$%&=*/!?_']))[\w.<>$%&=*/+\-!?_':]*)/,
symbol: $ => $._symbol,
keyword: $ => seq(choice(":", "::"), $._symbol),
nil: $ => "nil",
boolean: $ => choice("true", "false"),
character: $ => choice($._named, $._unicode, $._octal, $._any),
_unicode: $ => /\\u[0-9D-Fd-f][0-9a-fA-F]{3}/,
_octal: $ => /\\o[0-3][0-7]{2}/,
_any: $ => /\\./,
_named: $ => /\\(newline|return|space|tab|formfeed|backspace)/,
number: $ => choice($._int, $._ratio, $._float),
_int: $ => seq(optional(/[+-]/),
choice("0", /([1-9][0-9]*)/,
/0[xX]([0-9A-Fa-f]+)/,
/0([0-7]+)/,
/([1-9][0-9]?)[rR]([0-9A-Za-z]+)/,
/0[0-9]+/),
optional("N")),
_ratio: $ => /([-+]?[0-9]+)\/([0-9]+)/,
_float: $ => /([-+]?[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?/,
list: $ => seq('(', repeat($._form), ')'),
vector: $ => seq('[', repeat($._form), ']'),
map: $ => seq(
optional(choice("#::", seq("#:", $._symbol))), '{', repeat($._form), '}'
)
}
});