summaryrefslogtreecommitdiff
path: root/vim/treesitter/grammar.js
blob: 6644f81e0aee687e131f2d24c1a403c885120bb7 (plain) (blame)
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
// Tree-sitter grammar for the Fiddle hardware layout DSL.
// Mirrors the language accepted by src/Language/Fiddle/Parser.hs.

const commaSep1 = (rule) => seq(rule, repeat(seq(',', rule)));
const commaSep = (rule) => optional(commaSep1(rule));

module.exports = grammar({
  name: 'fiddle',

  extras: ($) => [/\s/, $.line_comment, $.doc_comment],

  word: ($) => $.identifier,

  rules: {
    source_file: ($) => repeat($.declaration),

    declaration: ($) =>
      seq(repeat($.directive), choice(
        $.option_decl,
        $.package_decl,
        $.using_decl,
        $.import_decl,
        $.location_decl,
        $.bits_decl,
        $.type_decl,
        $.instance_decl
      ), ';'),

    option_decl: ($) =>
      seq(
        'option',
        field('name', $.identifier),
        field('value', $.identifier)
      ),

    package_decl: ($) =>
      seq(
        'package',
        field('name', $.name),
        field('body', $.package_body)
      ),

    package_body: ($) =>
      seq(
        '{',
        repeat(seq(repeat($.directive), choice(
          $.option_decl,
          $.using_decl,
          $.import_decl,
          $.location_decl,
          $.bits_decl,
          $.type_decl,
          $.instance_decl
        ), ';')),
        '}'
      ),

    import_decl: ($) =>
      seq(
        'import',
        field('path', $.string),
        field('list', optional($.import_list))
      ),

    import_list: ($) => seq('(', commaSep1($.identifier), ')'),

    using_decl: ($) => seq('using', field('name', $.name)),

    location_decl: ($) =>
      seq(
        'location',
        field('name', $.identifier),
        '=',
        field('value', $.const_expression)
      ),

    bits_decl: ($) =>
      seq(
        'bits',
        field('name', $.identifier),
        ':',
        field('type', $.bit_type)
      ),

    bit_type: ($) =>
      choice(
        seq('(', field('width', $.expression), ')'),
        seq('enum', field('width', $.expr_paren), field('body', $.enum_body))
      ),

    enum_body: ($) =>
      seq('{', commaSep(seq(repeat($.directive), $.enum_constant)), optional(','), '}'),

    enum_constant: ($) =>
      choice(
        seq('reserved', '=', field('value', $.expression)),
        seq(field('name', $.identifier), '=', field('value', $.const_expression))
      ),

    type_decl: ($) =>
      seq(
        'type',
        field('name', $.identifier),
        ':',
        field('kind', $.body_type),
        field('body', $.obj_type_body)
      ),

    instance_decl: ($) =>
      seq(
        'instance',
        field('name', $.identifier),
        'at',
        field('address', $.expression),
        ':',
        field('type', $.obj_type)
      ),

    obj_type: ($) =>
      seq(
        field('base', choice(
          $.name,
          seq(field('kind', $.body_type), field('body', $.obj_type_body))
        )),
        repeat($.array_extent)
      ),

    obj_type_body: ($) =>
      seq(
        '{',
        repeat(seq(repeat($.directive), $.obj_type_decl, ';')),
        '}'
      ),

    obj_type_decl: ($) =>
      choice(
        seq('assert_pos', field('target', $.expr_paren)),
        seq('skip_to', field('offset', $.expr_paren)),
        seq('buffer', field('name', optional($.identifier)), field('size', $.expr_paren)),
        seq('reserved', field('size', $.expr_paren)),
        seq(field('kind', $.body_type), field('body', $.obj_type_body), field('name', optional($.identifier))),
        $.register_decl
      ),

    register_decl: ($) =>
      seq(
        field('modifier', optional($.modifier)),
        'reg',
        field('name', optional($.identifier)),
        field('width', $.expr_paren),
        field('position', optional(seq('@', $.number))),
        field('body', optional(seq(':', $.register_body)))
      ),

    modifier: ($) => choice('ro', 'rw', 'wo'),

    register_body: ($) =>
      seq(
        field('kind', $.bit_body_type),
        field('body', $.register_bits_body)
      ),

    bit_body_type: ($) => choice('struct', 'union'),

    register_bits_body: ($) =>
      seq(
        '{',
        repeat(seq(repeat($.directive), $.register_bits_decl, ';')),
        '}'
      ),

    register_bits_decl: ($) =>
      choice(
        seq('reserved', field('size', $.expr_paren)),
        seq(
          field('modifier', optional($.modifier)),
          choice(
            seq(field('body', $.register_body), field('name', optional($.identifier))),
            seq(
              field('name', $.identifier),
              ':',
              field('type', $.register_bits_type_ref)
            )
          )
        )
      ),

    register_bits_type_ref: ($) =>
      seq(
        field('base', choice(
          $.register_bits_width,
          $.anonymous_bits_type,
          $.name
        )),
        repeat($.array_extent)
      ),

    register_bits_width: ($) => seq('(', field('width', $.const_expression), ')'),

    anonymous_bits_type: ($) => seq('enum', field('width', $.expr_paren), field('body', $.enum_body)),

    expr_paren: ($) => seq('(', $.expression, ')'),

    array_extent: ($) => seq('[', field('size', $.const_expression), ']'),

    body_type: ($) => choice('struct', 'union'),

    const_expression: ($) => $.expression,

    expression: ($) => choice($.number, $.name),

    name: ($) => seq($.identifier, repeat(seq('.', $.identifier))),

    directive: ($) => seq('[[', commaSep($.directive_element), ']]'),

    directive_element: ($) =>
      choice(
        seq(
          field('backend', $.identifier),
          ':',
          field('key', $.identifier),
          optional(seq('=', field('value', $.directive_value)))
        ),
        seq(field('key', $.identifier), '=', field('value', $.directive_value)),
        field('key', $.identifier)
      ),

    directive_value: ($) => choice($.string, $.number),

    identifier: ($) => token(prec(-1, /[A-Za-z_][A-Za-z0-9_]*/)),

    number: ($) => token(/[0-9][0-9A-Za-z_]*/),

    string: ($) => token(seq('"', repeat(choice(/[^"\\]/, /\\./)), '"')),

    line_comment: ($) => token(seq('//', /.*/)),

    doc_comment: ($) => token(seq('/**', /[^*]*\*+(?:[^/*][^*]*\*+)*/, '/')),
  },
});