aboutsummaryrefslogtreecommitdiff
path: root/grammar.js
blob: 2f0e67b9ba40ad098d37d8c27c6a091da3434b78 (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
const IDENT = /\p{XID_Start}[-\p{XID_Continue}]*/u

module.exports = grammar({
	name: 'gsp',
	extras: $ => [/\p{Pattern_White_Space}+/u],
	rules: {
		document: $ => repeat($._toplevel),
		_toplevel: $ => choice($.comment, $.node),

		comment: $ => seq(
			'/',
			optional(seq(
				field('name', $.ident),
				optional(field('attrs', $.attr_list)),
			)),
			field('body', $.node_body),
		),
		node: $ => seq(
			field('name', $.ident),
			optional(field('attrs', $.attr_list)),
			field('body', $.node_body),
		),

		node_body: $ => seq(
			'{',
			choice(
				repeat($._toplevel),
				seq(choice('-', '='), optional($.text)),
			),
			'}',
		),

		attr_list: $ => repeat1(choice(
			$.attr,
			$.id_attr,
			$.class_attr,
		)),

		attr: $ => seq(
			field('name', $.ident),
			optional(seq('=', field('value', $.string))),
		),
		id_attr: $ => seq('#',
			field('name', alias(token.immediate(IDENT), $.ident))),
		class_attr: $ => seq('.',
			field('name', alias(token.immediate(IDENT), $.ident))),

		text: $ => repeat1(choice(
			/(\\[@}\\]|[^@}\\\p{Pattern_White_Space}])((\\[@}\\]|[^@}\\])*(\\[@}\\]|[^@}\\\p{Pattern_White_Space}]))?/u,
			seq('@', $._toplevel),
		)),
		ident: $ => IDENT,
		string: $ => /"(\\["\\]|[^"\\])+"/,
	},
})